(function(global, factory) {
	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
		typeof define === 'function' && define.amd ? define(['exports'], factory) :
		(factory((global.mapv = global.mapv || {})));
}(this, (function(exports) {
	'use strict';

	var version = "2.0.41";

	/**
	 * @author kyle / http://nikai.us/
	 */

	var clear = function(context) {
		context && context.clearRect && context.clearRect(0, 0, context.canvas.width, context.canvas.height);
		//context.canvas.width = context.canvas.width;
		//context.canvas.height = context.canvas.height;
	};

	/**
	 * @author kyle / http://nikai.us/
	 */

	var resolutionScale$1 = function(context) {
		var devicePixelRatio = window.devicePixelRatio || 1;
		context.canvas.width = context.canvas.width * devicePixelRatio;
		context.canvas.height = context.canvas.height * devicePixelRatio;
		context.canvas.style.width = context.canvas.width / devicePixelRatio + 'px';
		context.canvas.style.height = context.canvas.height / devicePixelRatio + 'px';
		context.scale(devicePixelRatio, devicePixelRatio);
	};

	function Event() {
		this._subscribers = {}; // event subscribers
	}

	/**
	 * Subscribe to an event, add an event listener
	 * @param {String} event        Event name. Available events: 'put', 'update',
	 *                              'remove'
	 * @param {function} callback   Callback method. Called with three parameters:
	 *                                  {String} event
	 *                                  {Object | null} params
	 *                                  {String | Number} senderId
	 */
	Event.prototype.on = function(event, callback) {
		var subscribers = this._subscribers[event];
		if (!subscribers) {
			subscribers = [];
			this._subscribers[event] = subscribers;
		}

		subscribers.push({
			callback: callback
		});
	};

	/**
	 * Unsubscribe from an event, remove an event listener
	 * @param {String} event
	 * @param {function} callback
	 */
	Event.prototype.off = function(event, callback) {
		var subscribers = this._subscribers[event];
		if (subscribers) {
			//this._subscribers[event] = subscribers.filter(listener => listener.callback != callback);
			for (var i = 0; i < subscribers.length; i++) {
				if (subscribers[i].callback == callback) {
					subscribers.splice(i, 1);
					i--;
				}
			}
		}
	};

	/**
	 * Trigger an event
	 * @param {String} event
	 * @param {Object | null} params
	 * @param {String} [senderId]       Optional id of the sender.
	 * @private
	 */
	Event.prototype._trigger = function(event, params, senderId) {
		if (event == '*') {
			throw new Error('Cannot trigger event *');
		}

		var subscribers = [];
		if (event in this._subscribers) {
			subscribers = subscribers.concat(this._subscribers[event]);
		}
		if ('*' in this._subscribers) {
			subscribers = subscribers.concat(this._subscribers['*']);
		}

		for (var i = 0, len = subscribers.length; i < len; i++) {
			var subscriber = subscribers[i];
			if (subscriber.callback) {
				subscriber.callback(event, params, senderId || null);
			}
		}
	};

	/**
	 * get the center by the city name
	 * @author kyle / http://nikai.us/
	 */

	var citycenter = {
		municipalities: [{
			n: "北京",
			g: "116.395645,39.929986|12"
		}, {
			n: "上海",
			g: "121.487899,31.249162|12"
		}, {
			n: "天津",
			g: "117.210813,39.14393|12"
		}, {
			n: "重庆",
			g: "106.530635,29.544606|12"
		}],
		provinces: [{
			n: "安徽",
			g: "117.216005,31.859252|8",
			cities: [{
				n: "合肥",
				g: "117.282699,31.866942|12"
			}, {
				n: "安庆",
				g: "117.058739,30.537898|13"
			}, {
				n: "蚌埠",
				g: "117.35708,32.929499|13"
			}, {
				n: "亳州",
				g: "115.787928,33.871211|13"
			}, {
				n: "巢湖",
				g: "117.88049,31.608733|13"
			}, {
				n: "池州",
				g: "117.494477,30.660019|14"
			}, {
				n: "滁州",
				g: "118.32457,32.317351|13"
			}, {
				n: "阜阳",
				g: "115.820932,32.901211|13"
			}, {
				n: "淮北",
				g: "116.791447,33.960023|13"
			}, {
				n: "淮南",
				g: "117.018639,32.642812|13"
			}, {
				n: "黄山",
				g: "118.29357,29.734435|13"
			}, {
				n: "六安",
				g: "116.505253,31.755558|13"
			}, {
				n: "马鞍山",
				g: "118.515882,31.688528|13"
			}, {
				n: "宿州",
				g: "116.988692,33.636772|13"
			}, {
				n: "铜陵",
				g: "117.819429,30.94093|14"
			}, {
				n: "芜湖",
				g: "118.384108,31.36602|12"
			}, {
				n: "宣城",
				g: "118.752096,30.951642|13"
			}]
		}, {
			n: "福建",
			g: "117.984943,26.050118|8",
			cities: [{
				n: "福州",
				g: "119.330221,26.047125|12"
			}, {
				n: "龙岩",
				g: "117.017997,25.078685|13"
			}, {
				n: "南平",
				g: "118.181883,26.643626|13"
			}, {
				n: "宁德",
				g: "119.542082,26.656527|14"
			}, {
				n: "莆田",
				g: "119.077731,25.44845|13"
			}, {
				n: "泉州",
				g: "118.600362,24.901652|12"
			}, {
				n: "三明",
				g: "117.642194,26.270835|14"
			}, {
				n: "厦门",
				g: "118.103886,24.489231|12"
			}, {
				n: "漳州",
				g: "117.676205,24.517065|12"
			}]
		}, {
			n: "甘肃",
			g: "102.457625,38.103267|6",
			cities: [{
				n: "兰州",
				g: "103.823305,36.064226|12"
			}, {
				n: "白银",
				g: "104.171241,36.546682|13"
			}, {
				n: "定西",
				g: "104.626638,35.586056|13"
			}, {
				n: "甘南州",
				g: "102.917442,34.992211|14"
			}, {
				n: "嘉峪关",
				g: "98.281635,39.802397|13"
			}, {
				n: "金昌",
				g: "102.208126,38.516072|13"
			}, {
				n: "酒泉",
				g: "98.508415,39.741474|13"
			}, {
				n: "临夏州",
				g: "103.215249,35.598514|13"
			}, {
				n: "陇南",
				g: "104.934573,33.39448|14"
			}, {
				n: "平凉",
				g: "106.688911,35.55011|13"
			}, {
				n: "庆阳",
				g: "107.644227,35.726801|13"
			}, {
				n: "天水",
				g: "105.736932,34.584319|13"
			}, {
				n: "武威",
				g: "102.640147,37.933172|13"
			}, {
				n: "张掖",
				g: "100.459892,38.93932|13"
			}]
		}, {
			n: "广东",
			g: "113.394818,23.408004|8",
			cities: [{
				n: "广州",
				g: "113.30765,23.120049|12"
			}, {
				n: "潮州",
				g: "116.630076,23.661812|13"
			}, {
				n: "东莞",
				g: "113.763434,23.043024|12"
			}, {
				n: "佛山",
				g: "113.134026,23.035095|13"
			}, {
				n: "河源",
				g: "114.713721,23.757251|12"
			}, {
				n: "惠州",
				g: "114.410658,23.11354|12"
			}, {
				n: "江门",
				g: "113.078125,22.575117|13"
			}, {
				n: "揭阳",
				g: "116.379501,23.547999|13"
			}, {
				n: "茂名",
				g: "110.931245,21.668226|13"
			}, {
				n: "梅州",
				g: "116.126403,24.304571|13"
			}, {
				n: "清远",
				g: "113.040773,23.698469|13"
			}, {
				n: "汕头",
				g: "116.72865,23.383908|13"
			}, {
				n: "汕尾",
				g: "115.372924,22.778731|14"
			}, {
				n: "韶关",
				g: "113.594461,24.80296|13"
			}, {
				n: "深圳",
				g: "114.025974,22.546054|12"
			}, {
				n: "阳江",
				g: "111.97701,21.871517|14"
			}, {
				n: "云浮",
				g: "112.050946,22.937976|13"
			}, {
				n: "湛江",
				g: "110.365067,21.257463|13"
			}, {
				n: "肇庆",
				g: "112.479653,23.078663|13"
			}, {
				n: "中山",
				g: "113.42206,22.545178|12"
			}, {
				n: "珠海",
				g: "113.562447,22.256915|13"
			}]
		}, {
			n: "广西",
			g: "108.924274,23.552255|7",
			cities: [{
				n: "南宁",
				g: "108.297234,22.806493|12"
			}, {
				n: "百色",
				g: "106.631821,23.901512|13"
			}, {
				n: "北海",
				g: "109.122628,21.472718|13"
			}, {
				n: "崇左",
				g: "107.357322,22.415455|14"
			}, {
				n: "防城港",
				g: "108.351791,21.617398|15"
			}, {
				n: "桂林",
				g: "110.26092,25.262901|12"
			}, {
				n: "贵港",
				g: "109.613708,23.103373|13"
			}, {
				n: "河池",
				g: "108.069948,24.699521|14"
			}, {
				n: "贺州",
				g: "111.552594,24.411054|14"
			}, {
				n: "来宾",
				g: "109.231817,23.741166|14"
			}, {
				n: "柳州",
				g: "109.422402,24.329053|12"
			}, {
				n: "钦州",
				g: "108.638798,21.97335|13"
			}, {
				n: "梧州",
				g: "111.305472,23.485395|13"
			}, {
				n: "玉林",
				g: "110.151676,22.643974|14"
			}]
		}, {
			n: "贵州",
			g: "106.734996,26.902826|8",
			cities: [{
				n: "贵阳",
				g: "106.709177,26.629907|12"
			}, {
				n: "安顺",
				g: "105.92827,26.228595|13"
			}, {
				n: "毕节地区",
				g: "105.300492,27.302612|14"
			}, {
				n: "六盘水",
				g: "104.852087,26.591866|13"
			}, {
				n: "铜仁地区",
				g: "109.196161,27.726271|14"
			}, {
				n: "遵义",
				g: "106.93126,27.699961|13"
			}, {
				n: "黔西南州",
				g: "104.900558,25.095148|11"
			}, {
				n: "黔东南州",
				g: "107.985353,26.583992|11"
			}, {
				n: "黔南州",
				g: "107.523205,26.264536|11"
			}]
		}, {
			n: "海南",
			g: "109.733755,19.180501|9",
			cities: [{
				n: "海口",
				g: "110.330802,20.022071|13"
			}, {
				n: "白沙",
				g: "109.358586,19.216056|12"
			}, {
				n: "保亭",
				g: "109.656113,18.597592|12"
			}, {
				n: "昌江",
				g: "109.0113,19.222483|12"
			}, {
				n: "儋州",
				g: "109.413973,19.571153|13"
			}, {
				n: "澄迈",
				g: "109.996736,19.693135|13"
			}, {
				n: "东方",
				g: "108.85101,18.998161|13"
			}, {
				n: "定安",
				g: "110.32009,19.490991|13"
			}, {
				n: "琼海",
				g: "110.414359,19.21483|13"
			}, {
				n: "琼中",
				g: "109.861849,19.039771|12"
			}, {
				n: "乐东",
				g: "109.062698,18.658614|12"
			}, {
				n: "临高",
				g: "109.724101,19.805922|13"
			}, {
				n: "陵水",
				g: "109.948661,18.575985|12"
			}, {
				n: "三亚",
				g: "109.522771,18.257776|12"
			}, {
				n: "屯昌",
				g: "110.063364,19.347749|13"
			}, {
				n: "万宁",
				g: "110.292505,18.839886|13"
			}, {
				n: "文昌",
				g: "110.780909,19.750947|13"
			}, {
				n: "五指山",
				g: "109.51775,18.831306|13"
			}]
		}, {
			n: "河北",
			g: "115.661434,38.61384|7",
			cities: [{
				n: "石家庄",
				g: "114.522082,38.048958|12"
			}, {
				n: "保定",
				g: "115.49481,38.886565|13"
			}, {
				n: "沧州",
				g: "116.863806,38.297615|13"
			}, {
				n: "承德",
				g: "117.933822,40.992521|14"
			}, {
				n: "邯郸",
				g: "114.482694,36.609308|13"
			}, {
				n: "衡水",
				g: "115.686229,37.746929|13"
			}, {
				n: "廊坊",
				g: "116.703602,39.518611|13"
			}, {
				n: "秦皇岛",
				g: "119.604368,39.945462|12"
			}, {
				n: "唐山",
				g: "118.183451,39.650531|13"
			}, {
				n: "邢台",
				g: "114.520487,37.069531|13"
			}, {
				n: "张家口",
				g: "114.893782,40.811188|13"
			}]
		}, {
			n: "河南",
			g: "113.486804,34.157184|7",
			cities: [{
				n: "郑州",
				g: "113.649644,34.75661|12"
			}, {
				n: "安阳",
				g: "114.351807,36.110267|12"
			}, {
				n: "鹤壁",
				g: "114.29777,35.755426|13"
			}, {
				n: "焦作",
				g: "113.211836,35.234608|13"
			}, {
				n: "开封",
				g: "114.351642,34.801854|13"
			}, {
				n: "洛阳",
				g: "112.447525,34.657368|12"
			}, {
				n: "漯河",
				g: "114.046061,33.576279|13"
			}, {
				n: "南阳",
				g: "112.542842,33.01142|13"
			}, {
				n: "平顶山",
				g: "113.300849,33.745301|13"
			}, {
				n: "濮阳",
				g: "115.026627,35.753298|12"
			}, {
				n: "三门峡",
				g: "111.181262,34.78332|13"
			}, {
				n: "商丘",
				g: "115.641886,34.438589|13"
			}, {
				n: "新乡",
				g: "113.91269,35.307258|13"
			}, {
				n: "信阳",
				g: "114.085491,32.128582|13"
			}, {
				n: "许昌",
				g: "113.835312,34.02674|13"
			}, {
				n: "周口",
				g: "114.654102,33.623741|13"
			}, {
				n: "驻马店",
				g: "114.049154,32.983158|13"
			}]
		}, {
			n: "黑龙江",
			g: "128.047414,47.356592|6",
			cities: [{
				n: "哈尔滨",
				g: "126.657717,45.773225|12"
			}, {
				n: "大庆",
				g: "125.02184,46.596709|12"
			}, {
				n: "大兴安岭地区",
				g: "124.196104,51.991789|10"
			}, {
				n: "鹤岗",
				g: "130.292472,47.338666|13"
			}, {
				n: "黑河",
				g: "127.50083,50.25069|14"
			}, {
				n: "鸡西",
				g: "130.941767,45.32154|13"
			}, {
				n: "佳木斯",
				g: "130.284735,46.81378|12"
			}, {
				n: "牡丹江",
				g: "129.608035,44.588521|13"
			}, {
				n: "七台河",
				g: "131.019048,45.775005|14"
			}, {
				n: "齐齐哈尔",
				g: "123.987289,47.3477|13"
			}, {
				n: "双鸭山",
				g: "131.171402,46.655102|13"
			}, {
				n: "绥化",
				g: "126.989095,46.646064|13"
			}, {
				n: "伊春",
				g: "128.910766,47.734685|14"
			}]
		}, {
			n: "湖北",
			g: "112.410562,31.209316|8",
			cities: [{
				n: "武汉",
				g: "114.3162,30.581084|12"
			}, {
				n: "鄂州",
				g: "114.895594,30.384439|14"
			}, {
				n: "恩施",
				g: "109.517433,30.308978|14"
			}, {
				n: "黄冈",
				g: "114.906618,30.446109|14"
			}, {
				n: "黄石",
				g: "115.050683,30.216127|13"
			}, {
				n: "荆门",
				g: "112.21733,31.042611|13"
			}, {
				n: "荆州",
				g: "112.241866,30.332591|12"
			}, {
				n: "潜江",
				g: "112.768768,30.343116|13"
			}, {
				n: "神农架林区",
				g: "110.487231,31.595768|13"
			}, {
				n: "十堰",
				g: "110.801229,32.636994|13"
			}, {
				n: "随州",
				g: "113.379358,31.717858|13"
			}, {
				n: "天门",
				g: "113.12623,30.649047|13"
			}, {
				n: "仙桃",
				g: "113.387448,30.293966|13"
			}, {
				n: "咸宁",
				g: "114.300061,29.880657|13"
			}, {
				n: "襄阳",
				g: "112.176326,32.094934|12"
			}, {
				n: "孝感",
				g: "113.935734,30.927955|13"
			}, {
				n: "宜昌",
				g: "111.310981,30.732758|13"
			}]
		}, {
			n: "湖南",
			g: "111.720664,27.695864|7",
			cities: [{
				n: "长沙",
				g: "112.979353,28.213478|12"
			}, {
				n: "常德",
				g: "111.653718,29.012149|12"
			}, {
				n: "郴州",
				g: "113.037704,25.782264|13"
			}, {
				n: "衡阳",
				g: "112.583819,26.898164|13"
			}, {
				n: "怀化",
				g: "109.986959,27.557483|13"
			}, {
				n: "娄底",
				g: "111.996396,27.741073|13"
			}, {
				n: "邵阳",
				g: "111.461525,27.236811|13"
			}, {
				n: "湘潭",
				g: "112.935556,27.835095|13"
			}, {
				n: "湘西州",
				g: "109.745746,28.317951|14"
			}, {
				n: "益阳",
				g: "112.366547,28.588088|13"
			}, {
				n: "永州",
				g: "111.614648,26.435972|13"
			}, {
				n: "岳阳",
				g: "113.146196,29.378007|13"
			}, {
				n: "张家界",
				g: "110.48162,29.124889|13"
			}, {
				n: "株洲",
				g: "113.131695,27.827433|13"
			}]
		}, {
			n: "江苏",
			g: "119.368489,33.013797|8",
			cities: [{
				n: "南京",
				g: "118.778074,32.057236|12"
			}, {
				n: "常州",
				g: "119.981861,31.771397|12"
			}, {
				n: "淮安",
				g: "119.030186,33.606513|12"
			}, {
				n: "连云港",
				g: "119.173872,34.601549|12"
			}, {
				n: "南通",
				g: "120.873801,32.014665|12"
			}, {
				n: "苏州",
				g: "120.619907,31.317987|12"
			}, {
				n: "宿迁",
				g: "118.296893,33.95205|13"
			}, {
				n: "泰州",
				g: "119.919606,32.476053|13"
			}, {
				n: "无锡",
				g: "120.305456,31.570037|12"
			}, {
				n: "徐州",
				g: "117.188107,34.271553|12"
			}, {
				n: "盐城",
				g: "120.148872,33.379862|12"
			}, {
				n: "扬州",
				g: "119.427778,32.408505|13"
			}, {
				n: "镇江",
				g: "119.455835,32.204409|13"
			}]
		}, {
			n: "江西",
			g: "115.676082,27.757258|7",
			cities: [{
				n: "南昌",
				g: "115.893528,28.689578|12"
			}, {
				n: "抚州",
				g: "116.360919,27.954545|13"
			}, {
				n: "赣州",
				g: "114.935909,25.845296|13"
			}, {
				n: "吉安",
				g: "114.992039,27.113848|13"
			}, {
				n: "景德镇",
				g: "117.186523,29.303563|12"
			}, {
				n: "九江",
				g: "115.999848,29.71964|13"
			}, {
				n: "萍乡",
				g: "113.859917,27.639544|13"
			}, {
				n: "上饶",
				g: "117.955464,28.457623|13"
			}, {
				n: "新余",
				g: "114.947117,27.822322|13"
			}, {
				n: "宜春",
				g: "114.400039,27.81113|13"
			}, {
				n: "鹰潭",
				g: "117.03545,28.24131|13"
			}]
		}, {
			n: "吉林",
			g: "126.262876,43.678846|7",
			cities: [{
				n: "长春",
				g: "125.313642,43.898338|12"
			}, {
				n: "白城",
				g: "122.840777,45.621086|13"
			}, {
				n: "白山",
				g: "126.435798,41.945859|13"
			}, {
				n: "吉林",
				g: "126.564544,43.871988|12"
			}, {
				n: "辽源",
				g: "125.133686,42.923303|13"
			}, {
				n: "四平",
				g: "124.391382,43.175525|12"
			}, {
				n: "松原",
				g: "124.832995,45.136049|13"
			}, {
				n: "通化",
				g: "125.94265,41.736397|13"
			}, {
				n: "延边",
				g: "129.485902,42.896414|13"
			}]
		}, {
			n: "辽宁",
			g: "122.753592,41.6216|8",
			cities: [{
				n: "沈阳",
				g: "123.432791,41.808645|12"
			}, {
				n: "鞍山",
				g: "123.007763,41.118744|13"
			}, {
				n: "本溪",
				g: "123.778062,41.325838|12"
			}, {
				n: "朝阳",
				g: "120.446163,41.571828|13"
			}, {
				n: "大连",
				g: "121.593478,38.94871|12"
			}, {
				n: "丹东",
				g: "124.338543,40.129023|12"
			}, {
				n: "抚顺",
				g: "123.92982,41.877304|12"
			}, {
				n: "阜新",
				g: "121.660822,42.01925|14"
			}, {
				n: "葫芦岛",
				g: "120.860758,40.74303|13"
			}, {
				n: "锦州",
				g: "121.147749,41.130879|13"
			}, {
				n: "辽阳",
				g: "123.172451,41.273339|14"
			}, {
				n: "盘锦",
				g: "122.073228,41.141248|13"
			}, {
				n: "铁岭",
				g: "123.85485,42.299757|13"
			}, {
				n: "营口",
				g: "122.233391,40.668651|13"
			}]
		}, {
			n: "内蒙古",
			g: "114.415868,43.468238|5",
			cities: [{
				n: "呼和浩特",
				g: "111.660351,40.828319|12"
			}, {
				n: "阿拉善盟",
				g: "105.695683,38.843075|14"
			}, {
				n: "包头",
				g: "109.846239,40.647119|12"
			}, {
				n: "巴彦淖尔",
				g: "107.423807,40.76918|12"
			}, {
				n: "赤峰",
				g: "118.930761,42.297112|12"
			}, {
				n: "鄂尔多斯",
				g: "109.993706,39.81649|12"
			}, {
				n: "呼伦贝尔",
				g: "119.760822,49.201636|12"
			}, {
				n: "通辽",
				g: "122.260363,43.633756|12"
			}, {
				n: "乌海",
				g: "106.831999,39.683177|13"
			}, {
				n: "乌兰察布",
				g: "113.112846,41.022363|12"
			}, {
				n: "锡林郭勒盟",
				g: "116.02734,43.939705|11"
			}, {
				n: "兴安盟",
				g: "122.048167,46.083757|11"
			}]
		}, {
			n: "宁夏",
			g: "106.155481,37.321323|8",
			cities: [{
				n: "银川",
				g: "106.206479,38.502621|12"
			}, {
				n: "固原",
				g: "106.285268,36.021523|13"
			}, {
				n: "石嘴山",
				g: "106.379337,39.020223|13"
			}, {
				n: "吴忠",
				g: "106.208254,37.993561|14"
			}, {
				n: "中卫",
				g: "105.196754,37.521124|14"
			}]
		}, {
			n: "青海",
			g: "96.202544,35.499761|7",
			cities: [{
				n: "西宁",
				g: "101.767921,36.640739|12"
			}, {
				n: "果洛州",
				g: "100.223723,34.480485|11"
			}, {
				n: "海东地区",
				g: "102.085207,36.51761|11"
			}, {
				n: "海北州",
				g: "100.879802,36.960654|11"
			}, {
				n: "海南州",
				g: "100.624066,36.284364|11"
			}, {
				n: "海西州",
				g: "97.342625,37.373799|11"
			}, {
				n: "黄南州",
				g: "102.0076,35.522852|11"
			}, {
				n: "玉树州",
				g: "97.013316,33.00624|14"
			}]
		}, {
			n: "山东",
			g: "118.527663,36.09929|8",
			cities: [{
				n: "济南",
				g: "117.024967,36.682785|12"
			}, {
				n: "滨州",
				g: "117.968292,37.405314|12"
			}, {
				n: "东营",
				g: "118.583926,37.487121|12"
			}, {
				n: "德州",
				g: "116.328161,37.460826|12"
			}, {
				n: "菏泽",
				g: "115.46336,35.26244|13"
			}, {
				n: "济宁",
				g: "116.600798,35.402122|13"
			}, {
				n: "莱芜",
				g: "117.684667,36.233654|13"
			}, {
				n: "聊城",
				g: "115.986869,36.455829|12"
			}, {
				n: "临沂",
				g: "118.340768,35.072409|12"
			}, {
				n: "青岛",
				g: "120.384428,36.105215|12"
			}, {
				n: "日照",
				g: "119.50718,35.420225|12"
			}, {
				n: "泰安",
				g: "117.089415,36.188078|13"
			}, {
				n: "威海",
				g: "122.093958,37.528787|13"
			}, {
				n: "潍坊",
				g: "119.142634,36.716115|12"
			}, {
				n: "烟台",
				g: "121.309555,37.536562|12"
			}, {
				n: "枣庄",
				g: "117.279305,34.807883|13"
			}, {
				n: "淄博",
				g: "118.059134,36.804685|12"
			}]
		}, {
			n: "山西",
			g: "112.515496,37.866566|7",
			cities: [{
				n: "太原",
				g: "112.550864,37.890277|12"
			}, {
				n: "长治",
				g: "113.120292,36.201664|12"
			}, {
				n: "大同",
				g: "113.290509,40.113744|12"
			}, {
				n: "晋城",
				g: "112.867333,35.499834|13"
			}, {
				n: "晋中",
				g: "112.738514,37.693362|13"
			}, {
				n: "临汾",
				g: "111.538788,36.099745|13"
			}, {
				n: "吕梁",
				g: "111.143157,37.527316|14"
			}, {
				n: "朔州",
				g: "112.479928,39.337672|13"
			}, {
				n: "忻州",
				g: "112.727939,38.461031|12"
			}, {
				n: "阳泉",
				g: "113.569238,37.869529|13"
			}, {
				n: "运城",
				g: "111.006854,35.038859|13"
			}]
		}, {
			n: "陕西",
			g: "109.503789,35.860026|7",
			cities: [{
				n: "西安",
				g: "108.953098,34.2778|12"
			}, {
				n: "安康",
				g: "109.038045,32.70437|13"
			}, {
				n: "宝鸡",
				g: "107.170645,34.364081|12"
			}, {
				n: "汉中",
				g: "107.045478,33.081569|13"
			}, {
				n: "商洛",
				g: "109.934208,33.873907|13"
			}, {
				n: "铜川",
				g: "108.968067,34.908368|13"
			}, {
				n: "渭南",
				g: "109.483933,34.502358|13"
			}, {
				n: "咸阳",
				g: "108.707509,34.345373|13"
			}, {
				n: "延安",
				g: "109.50051,36.60332|13"
			}, {
				n: "榆林",
				g: "109.745926,38.279439|12"
			}]
		}, {
			n: "四川",
			g: "102.89916,30.367481|7",
			cities: [{
				n: "成都",
				g: "104.067923,30.679943|12"
			}, {
				n: "阿坝州",
				g: "102.228565,31.905763|15"
			}, {
				n: "巴中",
				g: "106.757916,31.869189|14"
			}, {
				n: "达州",
				g: "107.494973,31.214199|14"
			}, {
				n: "德阳",
				g: "104.402398,31.13114|13"
			}, {
				n: "甘孜州",
				g: "101.969232,30.055144|15"
			}, {
				n: "广安",
				g: "106.63572,30.463984|13"
			}, {
				n: "广元",
				g: "105.819687,32.44104|13"
			}, {
				n: "乐山",
				g: "103.760824,29.600958|13"
			}, {
				n: "凉山州",
				g: "102.259591,27.892393|14"
			}, {
				n: "泸州",
				g: "105.44397,28.89593|14"
			}, {
				n: "南充",
				g: "106.105554,30.800965|13"
			}, {
				n: "眉山",
				g: "103.84143,30.061115|13"
			}, {
				n: "绵阳",
				g: "104.705519,31.504701|12"
			}, {
				n: "内江",
				g: "105.073056,29.599462|13"
			}, {
				n: "攀枝花",
				g: "101.722423,26.587571|14"
			}, {
				n: "遂宁",
				g: "105.564888,30.557491|12"
			}, {
				n: "雅安",
				g: "103.009356,29.999716|13"
			}, {
				n: "宜宾",
				g: "104.633019,28.769675|13"
			}, {
				n: "资阳",
				g: "104.63593,30.132191|13"
			}, {
				n: "自贡",
				g: "104.776071,29.359157|13"
			}]
		}, {
			n: "西藏",
			g: "89.137982,31.367315|6",
			cities: [{
				n: "拉萨",
				g: "91.111891,29.662557|13"
			}, {
				n: "阿里地区",
				g: "81.107669,30.404557|11"
			}, {
				n: "昌都地区",
				g: "97.185582,31.140576|15"
			}, {
				n: "林芝地区",
				g: "94.349985,29.666941|11"
			}, {
				n: "那曲地区",
				g: "92.067018,31.48068|14"
			}, {
				n: "日喀则地区",
				g: "88.891486,29.269023|14"
			}, {
				n: "山南地区",
				g: "91.750644,29.229027|11"
			}]
		}, {
			n: "新疆",
			g: "85.614899,42.127001|6",
			cities: [{
				n: "乌鲁木齐",
				g: "87.564988,43.84038|12"
			}, {
				n: "阿拉尔",
				g: "81.291737,40.61568|13"
			}, {
				n: "阿克苏地区",
				g: "80.269846,41.171731|12"
			}, {
				n: "阿勒泰地区",
				g: "88.137915,47.839744|13"
			}, {
				n: "巴音郭楞",
				g: "86.121688,41.771362|12"
			}, {
				n: "博尔塔拉州",
				g: "82.052436,44.913651|11"
			}, {
				n: "昌吉州",
				g: "87.296038,44.007058|13"
			}, {
				n: "哈密地区",
				g: "93.528355,42.858596|13"
			}, {
				n: "和田地区",
				g: "79.930239,37.116774|13"
			}, {
				n: "喀什地区",
				g: "75.992973,39.470627|12"
			}, {
				n: "克拉玛依",
				g: "84.88118,45.594331|13"
			}, {
				n: "克孜勒苏州",
				g: "76.137564,39.750346|11"
			}, {
				n: "石河子",
				g: "86.041865,44.308259|13"
			}, {
				n: "塔城地区",
				g: "82.974881,46.758684|12"
			}, {
				n: "图木舒克",
				g: "79.198155,39.889223|13"
			}, {
				n: "吐鲁番地区",
				g: "89.181595,42.96047|13"
			}, {
				n: "五家渠",
				g: "87.565449,44.368899|13"
			}, {
				n: "伊犁州",
				g: "81.297854,43.922248|11"
			}]
		}, {
			n: "云南",
			g: "101.592952,24.864213|7",
			cities: [{
				n: "昆明",
				g: "102.714601,25.049153|12"
			}, {
				n: "保山",
				g: "99.177996,25.120489|13"
			}, {
				n: "楚雄州",
				g: "101.529382,25.066356|13"
			}, {
				n: "大理州",
				g: "100.223675,25.5969|14"
			}, {
				n: "德宏州",
				g: "98.589434,24.44124|14"
			}, {
				n: "迪庆州",
				g: "99.713682,27.831029|14"
			}, {
				n: "红河州",
				g: "103.384065,23.367718|11"
			}, {
				n: "丽江",
				g: "100.229628,26.875351|13"
			}, {
				n: "临沧",
				g: "100.092613,23.887806|14"
			}, {
				n: "怒江州",
				g: "98.859932,25.860677|14"
			}, {
				n: "普洱",
				g: "100.980058,22.788778|14"
			}, {
				n: "曲靖",
				g: "103.782539,25.520758|12"
			}, {
				n: "昭通",
				g: "103.725021,27.340633|13"
			}, {
				n: "文山",
				g: "104.089112,23.401781|14"
			}, {
				n: "西双版纳",
				g: "100.803038,22.009433|13"
			}, {
				n: "玉溪",
				g: "102.545068,24.370447|13"
			}]
		}, {
			n: "浙江",
			g: "119.957202,29.159494|8",
			cities: [{
				n: "杭州",
				g: "120.219375,30.259244|12"
			}, {
				n: "湖州",
				g: "120.137243,30.877925|12"
			}, {
				n: "嘉兴",
				g: "120.760428,30.773992|13"
			}, {
				n: "金华",
				g: "119.652576,29.102899|12"
			}, {
				n: "丽水",
				g: "119.929576,28.4563|13"
			}, {
				n: "宁波",
				g: "121.579006,29.885259|12"
			}, {
				n: "衢州",
				g: "118.875842,28.95691|12"
			}, {
				n: "绍兴",
				g: "120.592467,30.002365|13"
			}, {
				n: "台州",
				g: "121.440613,28.668283|13"
			}, {
				n: "温州",
				g: "120.690635,28.002838|12"
			}, {
				n: "舟山",
				g: "122.169872,30.03601|13"
			}]
		}],
		other: [{
			n: "香港",
			g: "114.186124,22.293586|11"
		}, {
			n: "澳门",
			g: "113.557519,22.204118|13"
		}, {
			n: "台湾",
			g: "120.961454,23.80406|8"
		}]
	};

	function getCenter(g) {
		var item = g.split("|");
		item[0] = item[0].split(",");
		return {
			lng: parseFloat(item[0][0]),
			lat: parseFloat(item[0][1])
		};
	}

	var cityCenter = {
		getProvinceNameByCityName: function getProvinceNameByCityName(name) {
			var provinces = citycenter.provinces;
			for (var i = 0; i < provinces.length; i++) {
				var provinceName = provinces[i].n;
				var cities = provinces[i].cities;
				for (var j = 0; j < cities.length; j++) {
					if (cities[j].n == name) {
						return provinceName;
					}
				}
			}
			return null;
		},
		getCenterByCityName: function getCenterByCityName(name) {
			name = name.replace('市', '');
			for (var i = 0; i < citycenter.municipalities.length; i++) {
				if (citycenter.municipalities[i].n == name) {
					return getCenter(citycenter.municipalities[i].g);
				}
			}

			for (var i = 0; i < citycenter.other.length; i++) {
				if (citycenter.other[i].n == name) {
					return getCenter(citycenter.other[i].g);
				}
			}

			var provinces = citycenter.provinces;
			for (var i = 0; i < provinces.length; i++) {
				if (provinces[i].n == name) {
					return getCenter(provinces[i].g);
				}
				var cities = provinces[i].cities;
				for (var j = 0; j < cities.length; j++) {
					if (cities[j].n == name) {
						return getCenter(cities[j].g);
					}
				}
			}
			return null;
		}
	};

	var classCallCheck = function(instance, Constructor) {
		if (!(instance instanceof Constructor)) {
			throw new TypeError("Cannot call a class as a function");
		}
	};

	var createClass = function() {
		function defineProperties(target, props) {
			for (var i = 0; i < props.length; i++) {
				var descriptor = props[i];
				descriptor.enumerable = descriptor.enumerable || false;
				descriptor.configurable = true;
				if ("value" in descriptor) descriptor.writable = true;
				Object.defineProperty(target, descriptor.key, descriptor);
			}
		}

		return function(Constructor, protoProps, staticProps) {
			if (protoProps) defineProperties(Constructor.prototype, protoProps);
			if (staticProps) defineProperties(Constructor, staticProps);
			return Constructor;
		};
	}();







	var get = function get(object, property, receiver) {
		if (object === null) object = Function.prototype;
		var desc = Object.getOwnPropertyDescriptor(object, property);

		if (desc === undefined) {
			var parent = Object.getPrototypeOf(object);

			if (parent === null) {
				return undefined;
			} else {
				return get(parent, property, receiver);
			}
		} else if ("value" in desc) {
			return desc.value;
		} else {
			var getter = desc.get;

			if (getter === undefined) {
				return undefined;
			}

			return getter.call(receiver);
		}
	};

	var inherits = function(subClass, superClass) {
		if (typeof superClass !== "function" && superClass !== null) {
			throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
		}

		subClass.prototype = Object.create(superClass && superClass.prototype, {
			constructor: {
				value: subClass,
				enumerable: false,
				writable: true,
				configurable: true
			}
		});
		if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
			superClass;
	};











	var possibleConstructorReturn = function(self, call) {
		if (!self) {
			throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
		}

		return call && (typeof call === "object" || typeof call === "function") ? call : self;
	};

	/**
	 * @author kyle / http://nikai.us/
	 */

	/**
	 * DataSet
	 *
	 * A data set can:
	 * - add/remove/update data
	 * - gives triggers upon changes in the data
	 * - can  import/export data in various data formats
	 * @param {Array} [data]    Optional array with initial data
	 * the field geometry is like geojson, it can be:
	 * {
	 *     "type": "Point",
	 *     "coordinates": [125.6, 10.1]
	 * }
	 * {
	 *     "type": "LineString",
	 *     "coordinates": [
	 *         [102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]
	 *     ]
	 * }
	 * {
	 *     "type": "Polygon",
	 *     "coordinates": [
	 *         [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],
	 *           [100.0, 1.0], [100.0, 0.0] ]
	 *     ]
	 * }
	 * @param {Object} [options]   Available options:
	 * 
	 */
	function DataSet(data, options) {
		Event.bind(this)();

		this._options = options || {};
		this._data = []; // map with data indexed by id

		// add initial data when provided
		if (data) {
			this.add(data);
		}
	}

	DataSet.prototype = Event.prototype;

	/**
	 * Add data.
	 */
	DataSet.prototype.add = function(data, senderId) {
		if (Array.isArray(data)) {
			// Array
			for (var i = 0, len = data.length; i < len; i++) {
				if (data[i].time && data[i].time.length == 14 && data[i].time.substr(0, 2) == '20') {
					var time = data[i].time;
					data[i].time = new Date(time.substr(0, 4) + '-' + time.substr(4, 2) + '-' + time.substr(6, 2) + ' ' + time.substr(
						8, 2) + ':' + time.substr(10, 2) + ':' + time.substr(12, 2)).getTime();
				}
				this._data.push(data[i]);
			}
		} else if (data instanceof Object) {
			// Single item
			this._data.push(data);
		} else {
			throw new Error('Unknown dataType');
		}

		this._dataCache = JSON.parse(JSON.stringify(this._data));
	};

	DataSet.prototype.reset = function() {
		this._data = JSON.parse(JSON.stringify(this._dataCache));
	};

	/**
	 * get data.
	 */
	DataSet.prototype.get = function(args) {
		args = args || {};

		//console.time('copy data time')
		var start = new Date();
		// TODO: 不修改原始数据，在数据上挂载新的名称，每次修改数据直接修改新名称下的数据，可以省去deepCopy
		// var data = deepCopy(this._data);
		var data = this._data;

		var start = new Date();

		if (args.filter) {
			var newData = [];
			for (var i = 0; i < data.length; i++) {
				if (args.filter(data[i])) {
					newData.push(data[i]);
				}
			}
			data = newData;
		}

		if (args.transferCoordinate) {
			data = this.transferCoordinate(data, args.transferCoordinate, args.fromColumn, args.toColumn);
		}

		// console.timeEnd('transferCoordinate time')

		return data;
	};

	/**
	 * set data.
	 */
	DataSet.prototype.set = function(data) {
		this._set(data);
		this._trigger('change');
	};

	/**
	 * set data.
	 */
	DataSet.prototype._set = function(data) {
		this.clear();
		this.add(data);
	};

	/**
	 * clear data.
	 */
	DataSet.prototype.clear = function(args) {
		this._data = []; // map with data indexed by id
	};

	/**
	 * remove data.
	 */
	DataSet.prototype.remove = function(args) {};

	/**
	 * update data.
	 */
	DataSet.prototype.update = function(cbk, condition) {

		var data = this._data;

		var item = null;
		for (var i = 0; i < data.length; i++) {
			if (condition) {
				var flag = true;
				for (var key in condition) {
					if (data[i][key] != condition[key]) {
						flag = false;
					}
				}
				if (flag) {
					cbk && cbk(data[i]);
				}
			} else {
				cbk && cbk(data[i]);
			}
		}

		this._dataCache = JSON.parse(JSON.stringify(this._data));

		this._trigger('change');
	};

	/**
	 * transfer coordinate.
	 */
	DataSet.prototype.transferCoordinate = function(data, transferFn, fromColumn, toColumnName) {

		toColumnName = toColumnName || '_coordinates';
		fromColumn = fromColumn || 'coordinates';

		for (var i = 0; i < data.length; i++) {

			var geometry = data[i].geometry;
			var coordinates = geometry[fromColumn];
			switch (geometry.type) {
				case 'Point':
					geometry[toColumnName] = transferFn(coordinates);
					break;
				case 'LineString':
					var newCoordinates = [];
					for (var j = 0; j < coordinates.length; j++) {
						newCoordinates.push(transferFn(coordinates[j]));
					}
					geometry[toColumnName] = newCoordinates;
					break;
				case 'MultiLineString':
				case 'Polygon':
					var newCoordinates = getPolygon(coordinates);
					geometry[toColumnName] = newCoordinates;
					break;
				case 'MultiPolygon':
					var newCoordinates = [];
					for (var c = 0; c < coordinates.length; c++) {
						var polygon = coordinates[c];
						var polygon = getPolygon(polygon);
						newCoordinates.push(polygon);
					}

					geometry[toColumnName] = newCoordinates;
					break;
			}
		}

		function getPolygon(coordinates) {
			var newCoordinates = [];
			for (var c = 0; c < coordinates.length; c++) {
				var coordinate = coordinates[c];
				var newcoordinate = [];
				for (var j = 0; j < coordinate.length; j++) {
					newcoordinate.push(transferFn(coordinate[j]));
				}
				newCoordinates.push(newcoordinate);
			}
			return newCoordinates;
		}

		return data;
	};

	DataSet.prototype.initGeometry = function(transferFn) {

		if (transferFn) {

			this._data.forEach(function(item) {
				item.geometry = transferFn(item);
			});
		} else {

			this._data.forEach(function(item) {
				if (!item.geometry) {
					if (item.lng && item.lat) {
						item.geometry = {
							type: 'Point',
							coordinates: [item.lng, item.lat]
						};
					} else if (item.city) {
						var center = cityCenter.getCenterByCityName(item.city);
						if (center) {
							item.geometry = {
								type: 'Point',
								coordinates: [center.lng, center.lat]
							};
						}
					}
				}
			});
		}
	};

	/**
	 * 获取当前列的最大值
	 */
	DataSet.prototype.getMax = function(columnName) {
		var data = this._data;

		if (!data || data.length <= 0) {
			return;
		}

		var max = parseFloat(data[0][columnName]);

		for (var i = 1; i < data.length; i++) {
			var value = parseFloat(data[i][columnName]);
			if (value > max) {
				max = value;
			}
		}

		return max;
	};

	/**
	 * 获取当前列的总和
	 */
	DataSet.prototype.getSum = function(columnName) {
		var data = this._data;

		if (!data || data.length <= 0) {
			return;
		}

		var sum = 0;

		for (var i = 0; i < data.length; i++) {
			if (data[i][columnName]) {
				sum += parseFloat(data[i][columnName]);
			}
		}

		return sum;
	};

	/**
	 * 获取当前列的最小值
	 */
	DataSet.prototype.getMin = function(columnName) {
		var data = this._data;

		if (!data || data.length <= 0) {
			return;
		}

		var min = parseFloat(data[0][columnName]);

		for (var i = 1; i < data.length; i++) {
			var value = parseFloat(data[i][columnName]);
			if (value < min) {
				min = value;
			}
		}

		return min;
	};

	/**
	 * 获取去重的数据
	 */
	DataSet.prototype.getUnique = function(columnName) {
		var data = this._data;

		if (!data || data.length <= 0) {
			return;
		}

		var maps = {};

		for (var i = 1; i < data.length; i++) {
			maps[data[i][columnName]] = true;
		}

		var data = [];
		for (var key in maps) {
			data.push(key);
		}

		return data;
	};

	function hex_corner(center, size, i) {
		var angle_deg = 60 * i + 30;
		var angle_rad = Math.PI / 180 * angle_deg;
		return [center.x + size * Math.cos(angle_rad), center.y + size * Math.sin(angle_rad)];
	}

	function draw(context, x, y, size) {

		for (var j = 0; j < 6; j++) {

			var result = hex_corner({
				x: x,
				y: y
			}, size, j);

			context.lineTo(result[0], result[1]);
		}
	}

	/**
	 * @author kyle / http://nikai.us/
	 */

	var pathSimple = {
		drawDataSet: function drawDataSet(context, dataSet, options) {

			var data = dataSet instanceof DataSet ? dataSet.get() : dataSet;

			for (var i = 0, len = data.length; i < len; i++) {
				var item = data[i];
				this.draw(context, item, options);
			}
		},
		draw: function draw$$1(context, data, options) {
			var type = data.geometry.type;
			var coordinates = data.geometry._coordinates || data.geometry.coordinates;
			var symbol = data.symbol || options.symbol || 'circle';
			switch (type) {
				case 'Point':
					var size = data._size || data.size || options._size || options.size || 5;
					if (symbol === 'circle') {
						if (options.bigData === 'Point') {
							context.moveTo(coordinates[0], coordinates[1]);
						}
						context.arc(coordinates[0], coordinates[1], size, 0, Math.PI * 2);
					} else if (symbol === 'rect') {
						context.rect(coordinates[0] - size / 2, coordinates[1] - size / 2, size, size);
					} else if (symbol === 'honeycomb') {
						draw(context, coordinates[0], coordinates[1], size);
					}
					break;
				case 'LineString':
					this.drawLineString(context, coordinates);
					break;
				case 'MultiLineString':
					for (var i = 0; i < coordinates.length; i++) {
						var lineString = coordinates[i];
						this.drawLineString(context, lineString);
					}
					break;
				case 'Polygon':
					this.drawPolygon(context, coordinates);
					break;
				case 'MultiPolygon':
					for (var i = 0; i < coordinates.length; i++) {
						var polygon = coordinates[i];
						this.drawPolygon(context, polygon);
						if (options.multiPolygonDraw) {
							var flag = options.multiPolygonDraw();
							if (flag) {
								return flag;
							}
						}
					}
					break;
				default:
					console.error('type' + type + 'is not support now!');
					break;
			}
		},

		drawLineString: function drawLineString(context, coordinates) {
			for (var j = 0; j < coordinates.length; j++) {
				var x = coordinates[j][0];
				var y = coordinates[j][1];
				if (j == 0) {
					context.moveTo(x, y);
				} else {
					context.lineTo(x, y);
				}
			}
		},

		drawPolygon: function drawPolygon(context, coordinates) {
			context.beginPath();

			for (var i = 0; i < coordinates.length; i++) {
				var coordinate = coordinates[i];

				context.moveTo(coordinate[0][0], coordinate[0][1]);
				for (var j = 1; j < coordinate.length; j++) {
					context.lineTo(coordinate[j][0], coordinate[j][1]);
				}
				context.lineTo(coordinate[0][0], coordinate[0][1]);
				context.closePath();
			}
		}

	};

	/**
	 * @author kyle / http://nikai.us/
	 */

	var drawSimple = {
		draw: function draw(context, dataSet, options) {

			var data = dataSet instanceof DataSet ? dataSet.get() : dataSet;

			// console.log('xxxx',options)
			context.save();

			for (var key in options) {
				context[key] = options[key];
			}

			// console.log(data);
			if (options.bigData) {
				context.save();
				context.beginPath();

				for (var i = 0, len = data.length; i < len; i++) {

					var item = data[i];

					pathSimple.draw(context, item, options);
				}

				var type = options.bigData;

				if (type == 'Point' || type == 'Polygon' || type == 'MultiPolygon') {

					context.fill();

					if (context.lineDash) {
						context.setLineDash(context.lineDash);
					}

					if (item.lineDash) {
						context.setLineDash(item.lineDash);
					}

					if ((item.strokeStyle || options.strokeStyle) && options.lineWidth) {
						context.stroke();
					}
				} else if (type == 'LineString' || type == 'MultiLineString') {
					context.stroke();
				}

				context.restore();
			} else {

				for (var i = 0, len = data.length; i < len; i++) {

					var item = data[i];

					context.save();

					if (item.fillStyle || item._fillStyle) {
						context.fillStyle = item.fillStyle || item._fillStyle;
					}

					if (item.strokeStyle || item._strokeStyle) {
						context.strokeStyle = item.strokeStyle || item._strokeStyle;
					}

					if (context.lineDash) {
						context.setLineDash(context.lineDash);
					}

					if (item.lineDash) {
						context.setLineDash(item.lineDash);
					}

					var type = item.geometry.type;

					context.beginPath();

					options.multiPolygonDraw = function() {
						context.fill();

						if ((item.strokeStyle || options.strokeStyle) && options.lineWidth) {
							context.stroke();
						}
					};
					pathSimple.draw(context, item, options);

					if (type == 'Point' || type == 'Polygon' || type == 'MultiPolygon') {

						context.fill();

						if ((item.strokeStyle || options.strokeStyle) && options.lineWidth) {
							context.stroke();
						}
					} else if (type == 'LineString' || type == 'MultiLineString') {
						if (item.lineWidth || item._lineWidth) {
							context.lineWidth = item.lineWidth || item._lineWidth;
						}
						context.stroke();
					}

					context.restore();
				}
			}

			context.restore();
		}
	};

	function Canvas(width, height) {

		var canvas;

		if (typeof document === 'undefined') {

			// var Canvas = require('canvas');
			// canvas = new Canvas(width, height);

		} else {

			var canvas = document.createElement('canvas');

			if (width) {
				canvas.width = width;
			}

			if (height) {
				canvas.height = height;
			}
		}

		return canvas;
	}

	/**
	 * @author kyle / http://nikai.us/
	 */

	/**
	 * Category
	 * @param {Object} [options]   Available options:
	 *                             {Object} gradient: { 0.25: "rgb(0,0,255)", 0.55: "rgb(0,255,0)", 0.85: "yellow", 1.0: "rgb(255,0,0)"}
	 */
	function Intensity(options) {

		options = options || {};
		this.gradient = options.gradient || {
			0.25: "rgba(0, 0, 255, 1)",
			0.55: "rgba(0, 255, 0, 1)",
			0.85: "rgba(255, 255, 0, 1)",
			1.0: "rgba(255, 0, 0, 1)"
		};
		this.maxSize = options.maxSize || 35;
		this.minSize = options.minSize || 0;
		this.max = options.max || 100;
		this.min = options.min || 0;
		this.initPalette();
	}

	Intensity.prototype.setMax = function(value) {
		this.max = value || 100;
	};

	Intensity.prototype.setMin = function(value) {
		this.min = value || 0;
	};

	Intensity.prototype.setMaxSize = function(maxSize) {
		this.maxSize = maxSize || 35;
	};

	Intensity.prototype.setMinSize = function(minSize) {
		this.minSize = minSize || 0;
	};

	Intensity.prototype.initPalette = function() {

		var gradient = this.gradient;

		var canvas = new Canvas(256, 1);

		var paletteCtx = this.paletteCtx = canvas.getContext('2d');

		var lineGradient = paletteCtx.createLinearGradient(0, 0, 256, 1);

		for (var key in gradient) {
			lineGradient.addColorStop(parseFloat(key), gradient[key]);
		}

		paletteCtx.fillStyle = lineGradient;
		paletteCtx.fillRect(0, 0, 256, 1);
	};

	Intensity.prototype.getColor = function(value) {

		var imageData = this.getImageData(value);

		return "rgba(" + imageData[0] + ", " + imageData[1] + ", " + imageData[2] + ", " + imageData[3] / 256 + ")";
	};

	Intensity.prototype.getImageData = function(value) {

		var imageData = this.paletteCtx.getImageData(0, 0, 256, 1).data;

		if (value === undefined) {
			return imageData;
		}

		var max = this.max;
		var min = this.min;

		if (value > max) {
			value = max;
		}

		if (value < min) {
			value = min;
		}

		var index = Math.floor((value - min) / (max - min) * (256 - 1)) * 4;

		return [imageData[index], imageData[index + 1], imageData[index + 2], imageData[index + 3]];
	};

	/**
	 * @param Number value 
	 * @param Number max of value
	 * @param Number max of size
	 * @param Object other options
	 */
	Intensity.prototype.getSize = function(value) {

		var size = 0;
		var max = this.max;
		var min = this.min;
		var maxSize = this.maxSize;
		var minSize = this.minSize;

		if (value > max) {
			value = max;
		}

		if (value < min) {
			value = min;
		}

		if (max > min) {
			size = minSize + (value - min) / (max - min) * (maxSize - minSize);
		} else {
			return maxSize;
		}

		return size;
	};

	Intensity.prototype.getLegend = function(options) {
		var gradient = this.gradient;

		var width = options.width || 20;
		var height = options.height || 180;

		var canvas = new Canvas(width, height);

		var paletteCtx = canvas.getContext('2d');

		var lineGradient = paletteCtx.createLinearGradient(0, height, 0, 0);

		for (var key in gradient) {
			lineGradient.addColorStop(parseFloat(key), gradient[key]);
		}

		paletteCtx.fillStyle = lineGradient;
		paletteCtx.fillRect(0, 0, width, height);

		return canvas;
	};

	var global$1 = typeof window === 'undefined' ? {} : window;

	var devicePixelRatio = global$1.devicePixelRatio || 1;

	/**
	 * @author kyle / http://nikai.us/
	 */

	function createCircle(size) {

		var shadowBlur = size / 2;
		var r2 = size + shadowBlur;
		var offsetDistance = 10000;

		var circle = new Canvas(r2 * 2, r2 * 2);
		var context = circle.getContext('2d');

		context.shadowBlur = shadowBlur;
		context.shadowColor = 'black';
		context.shadowOffsetX = context.shadowOffsetY = offsetDistance;

		context.beginPath();
		context.arc(r2 - offsetDistance, r2 - offsetDistance, size, 0, Math.PI * 2, true);
		context.closePath();
		context.fill();
		return circle;
	}

	function colorize(pixels, gradient, options) {
		var max = getMax(options);
		var min = getMin(options);
		var diff = max - min;
		var range = options.range || null;

		var jMin = 0;
		var jMax = 1024;
		if (range && range.length === 2) {
			jMin = (range[0] - min) / diff * 1024;
		}

		if (range && range.length === 2) {
			jMax = (range[1] - min) / diff * 1024;
		}

		var maxOpacity = options.maxOpacity || 0.8;
		var range = options.range;

		for (var i = 3, len = pixels.length, j; i < len; i += 4) {
			j = pixels[i] * 4; // get gradient color from opacity value

			if (pixels[i] / 256 > maxOpacity) {
				pixels[i] = 256 * maxOpacity;
			}

			if (j && j >= jMin && j <= jMax) {
				pixels[i - 3] = gradient[j];
				pixels[i - 2] = gradient[j + 1];
				pixels[i - 1] = gradient[j + 2];
			} else {
				pixels[i] = 0;
			}
		}
	}

	function getMax(options) {
		var max = options.max || 100;
		return max;
	}

	function getMin(options) {
		var min = options.min || 0;
		return min;
	}

	function drawGray(context, dataSet, options) {

		var max = getMax(options);
		var min = getMin(options);
		// console.log(max)
		var size = options._size;
		if (size == undefined) {
			size = options.size;
			if (size == undefined) {
				size = 13;
			}
		}

		var intensity = new Intensity({
			gradient: options.gradient,
			max: max,
			min: min
		});

		var circle = createCircle(size);
		var circleHalfWidth = circle.width / 2;
		var circleHalfHeight = circle.height / 2;

		var data = dataSet;

		var dataOrderByAlpha = {};

		data.forEach(function(item, index) {
			var count = item.count === undefined ? 1 : item.count;
			var alpha = Math.min(1, count / max).toFixed(2);
			dataOrderByAlpha[alpha] = dataOrderByAlpha[alpha] || [];
			dataOrderByAlpha[alpha].push(item);
		});

		for (var i in dataOrderByAlpha) {
			if (isNaN(i)) continue;
			var _data = dataOrderByAlpha[i];
			context.beginPath();
			if (!options.withoutAlpha) {
				context.globalAlpha = i;
			}
			context.strokeStyle = intensity.getColor(i * max);
			_data.forEach(function(item, index) {
				if (!item.geometry) {
					return;
				}

				var coordinates = item.geometry._coordinates || item.geometry.coordinates;
				var type = item.geometry.type;
				if (type === 'Point') {
					var count = item.count === undefined ? 1 : item.count;
					context.globalAlpha = count / max;
					context.drawImage(circle, coordinates[0] - circleHalfWidth, coordinates[1] - circleHalfHeight);
				} else if (type === 'LineString') {
					var count = item.count === undefined ? 1 : item.count;
					context.globalAlpha = count / max;
					context.beginPath();
					pathSimple.draw(context, item, options);
					context.stroke();
				} else if (type === 'Polygon') {}
			});
		}
	}

	function draw$1(context, dataSet, options) {
		if (context.canvas.width <= 0 || context.canvas.height <= 0) {
			return;
		}

		var strength = options.strength || 0.3;
		context.strokeStyle = 'rgba(0,0,0,' + strength + ')';

		var shadowCanvas = new Canvas(context.canvas.width, context.canvas.height);
		var shadowContext = shadowCanvas.getContext('2d');
		shadowContext.scale(devicePixelRatio, devicePixelRatio);

		options = options || {};

		var data = dataSet instanceof DataSet ? dataSet.get() : dataSet;

		context.save();

		var intensity = new Intensity({
			gradient: options.gradient
		});

		//console.time('drawGray')
		drawGray(shadowContext, data, options);

		//console.timeEnd('drawGray');
		// return false;
		if (!options.absolute) {
			//console.time('changeColor');
			var colored = shadowContext.getImageData(0, 0, context.canvas.width, context.canvas.height);
			colorize(colored.data, intensity.getImageData(), options);
			//console.timeEnd('changeColor');
			context.putImageData(colored, 0, 0);

			context.restore();
		}

		intensity = null;
		shadowCanvas = null;
	}

	var drawHeatmap = {
		draw: draw$1
	};

	/**
	 * @author kyle / http://nikai.us/
	 */

	var drawGrid = {
		draw: function draw(context, dataSet, options) {

			context.save();

			var data = dataSet instanceof DataSet ? dataSet.get() : dataSet;

			var grids = {};

			var size = options._size || options.size || 50;

			var offset = options.offset || {
				x: 0,
				y: 0
			};

			for (var i = 0; i < data.length; i++) {
				var coordinates = data[i].geometry._coordinates || data[i].geometry.coordinates;
				var gridKey = Math.floor((coordinates[0] - offset.x) / size) + "," + Math.floor((coordinates[1] - offset.y) /
					size);
				if (!grids[gridKey]) {
					grids[gridKey] = 0;
				}
				grids[gridKey] += ~~(data[i].count || 1);
			}

			var intensity = new Intensity({
				min: options.min || 0,
				max: options.max || 100,
				gradient: options.gradient
			});

			for (var gridKey in grids) {
				gridKey = gridKey.split(",");

				context.beginPath();
				context.rect(gridKey[0] * size + .5 + offset.x, gridKey[1] * size + .5 + offset.y, size, size);
				context.fillStyle = intensity.getColor(grids[gridKey]);
				context.fill();
				if (options.strokeStyle && options.lineWidth) {
					context.stroke();
				}
			}

			if (options.label && options.label.show !== false) {

				context.fillStyle = options.label.fillStyle || 'white';

				if (options.label.font) {
					context.font = options.label.font;
				}

				if (options.label.shadowColor) {
					context.shadowColor = options.label.shadowColor;
				}

				if (options.label.shadowBlur) {
					context.shadowBlur = options.label.shadowBlur;
				}

				for (var gridKey in grids) {
					gridKey = gridKey.split(",");
					var text = grids[gridKey];
					var textWidth = context.measureText(text).width;
					context.fillText(text, gridKey[0] * size + .5 + offset.x + size / 2 - textWidth / 2, gridKey[1] * size + .5 +
						offset.y + size / 2 + 5);
				}
			}

			context.restore();
		}
	};

	/**
	 * @author kyle / http://nikai.us/
	 */

	function hex_corner$1(center, size, i) {
		var angle_deg = 60 * i + 30;
		var angle_rad = Math.PI / 180 * angle_deg;
		return [center.x + size * Math.cos(angle_rad), center.y + size * Math.sin(angle_rad)];
	}

	var drawHoneycomb = {
		draw: function draw(context, dataSet, options) {

			context.save();

			var data = dataSet instanceof DataSet ? dataSet.get() : dataSet;

			for (var key in options) {
				context[key] = options[key];
			}

			var grids = {};

			var offset = options.offset || {
				x: 10,
				y: 10
			};

			var r = options._size || options.size || 40;
			r = r / 2 / Math.sin(Math.PI / 3);
			var dx = r * 2 * Math.sin(Math.PI / 3);
			var dy = r * 1.5;

			var binsById = {};

			for (var i = 0; i < data.length; i++) {
				var coordinates = data[i].geometry._coordinates || data[i].geometry.coordinates;
				var py = (coordinates[1] - offset.y) / dy,
					pj = Math.round(py),
					px = (coordinates[0] - offset.x) / dx - (pj & 1 ? .5 : 0),
					pi = Math.round(px),
					py1 = py - pj;

				if (Math.abs(py1) * 3 > 1) {
					var px1 = px - pi,
						pi2 = pi + (px < pi ? -1 : 1) / 2,
						pj2 = pj + (py < pj ? -1 : 1),
						px2 = px - pi2,
						py2 = py - pj2;
					if (px1 * px1 + py1 * py1 > px2 * px2 + py2 * py2) pi = pi2 + (pj & 1 ? 1 : -1) / 2, pj = pj2;
				}

				var id = pi + "-" + pj,
					bin = binsById[id];
				if (bin) {
					bin.push(data[i]);
				} else {
					bin = binsById[id] = [data[i]];
					bin.i = pi;
					bin.j = pj;
					bin.x = (pi + (pj & 1 ? 1 / 2 : 0)) * dx;
					bin.y = pj * dy;
				}
			}

			var intensity = new Intensity({
				max: options.max || 100,
				maxSize: r,
				gradient: options.gradient
			});

			for (var key in binsById) {

				var item = binsById[key];

				context.beginPath();

				for (var j = 0; j < 6; j++) {

					var result = hex_corner$1({
						x: item.x + offset.x,
						y: item.y + offset.y
					}, r, j);

					context.lineTo(result[0], result[1]);
				}

				context.closePath();

				var count = 0;
				for (var i = 0; i < item.length; i++) {
					count += item[i].count || 1;
				}
				item.count = count;

				context.fillStyle = intensity.getColor(count);
				context.fill();
				if (options.strokeStyle && options.lineWidth) {
					context.stroke();
				}
			}

			if (options.label && options.label.show !== false) {

				context.fillStyle = options.label.fillStyle || 'white';

				if (options.label.font) {
					context.font = options.label.font;
				}

				if (options.label.shadowColor) {
					context.shadowColor = options.label.shadowColor;
				}

				if (options.label.shadowBlur) {
					context.shadowBlur = options.label.shadowBlur;
				}

				for (var key in binsById) {
					var item = binsById[key];
					var text = item.count;
					if (text < 0) {
						text = text.toFixed(2);
					} else {
						text = ~~text;
					}
					var textWidth = context.measureText(text).width;
					context.fillText(text, item.x + offset.x - textWidth / 2, item.y + offset.y + 5);
				}
			}

			context.restore();
		}
	};

	function createShader(gl, src, type) {
		var shader = gl.createShader(type);
		gl.shaderSource(shader, src);
		gl.compileShader(shader);
		return shader;
	}

	function initShaders(gl, vs_source, fs_source) {

		var vertexShader = createShader(gl, vs_source, gl.VERTEX_SHADER);
		var fragmentShader = createShader(gl, fs_source, gl.FRAGMENT_SHADER);

		var glProgram = gl.createProgram();

		gl.attachShader(glProgram, vertexShader);
		gl.attachShader(glProgram, fragmentShader);
		gl.linkProgram(glProgram);

		gl.useProgram(glProgram);

		return glProgram;
	}

	function getColorData(color) {
		var tmpCanvas = document.createElement('canvas');
		var tmpCtx = tmpCanvas.getContext('2d');
		tmpCanvas.width = 1;
		tmpCanvas.height = 1;
		tmpCtx.fillStyle = color;
		tmpCtx.fillRect(0, 0, 1, 1);
		return tmpCtx.getImageData(0, 0, 1, 1).data;
	}

	var vs_s = ['attribute vec4 a_Position;', 'void main() {', 'gl_Position = a_Position;', 'gl_PointSize = 30.0;', '}']
		.join('');

	var fs_s = ['precision mediump float;', 'uniform vec4 u_FragColor;', 'void main() {', 'gl_FragColor = u_FragColor;',
		'}'
	].join('');

	function draw$2(gl, data, options) {

		if (!data) {
			return;
		}

		var program = initShaders(gl, vs_s, fs_s);

		gl.enable(gl.BLEND);
		gl.blendFunc(gl.SRC_ALPHA, gl.ONE);

		//gl.clearColor(0.0, 0.0, 1.0, 1.0);
		gl.clear(gl.COLOR_BUFFER_BIT);

		var halfCanvasWidth = gl.canvas.width / 2;
		var halfCanvasHeight = gl.canvas.height / 2;

		// Create a buffer object
		var vertexBuffer = gl.createBuffer();
		// Bind the buffer object to target
		gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);

		var a_Position = gl.getAttribLocation(program, 'a_Position');
		// Assign the buffer object to a_Position variable
		gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);

		// Enable the assignment to a_Position variable
		gl.enableVertexAttribArray(a_Position);

		var uFragColor = gl.getUniformLocation(program, 'u_FragColor');

		var colored = getColorData(options.strokeStyle || 'red');

		gl.uniform4f(uFragColor, colored[0] / 255, colored[1] / 255, colored[2] / 255, colored[3] / 255);

		gl.lineWidth(options.lineWidth || 1);

		for (var i = 0, len = data.length; i < len; i++) {
			var _geometry = data[i].geometry._coordinates;

			var verticesData = [];

			for (var j = 0; j < _geometry.length; j++) {
				var item = _geometry[j];

				var x = (item[0] - halfCanvasWidth) / halfCanvasWidth;
				var y = (halfCanvasHeight - item[1]) / halfCanvasHeight;
				verticesData.push(x, y);
			}

			var vertices = new Float32Array(verticesData);
			// Write date into the buffer object
			gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
			gl.drawArrays(gl.LINE_STRIP, 0, _geometry.length);
		}
	}

	var line = {
		draw: draw$2
	};

	var vs_s$1 = ['attribute vec4 a_Position;', 'attribute float a_PointSize;', 'void main() {',
		'gl_Position = a_Position;', 'gl_PointSize = a_PointSize;', '}'
	].join('');

	var fs_s$1 = ['precision mediump float;', 'uniform vec4 u_FragColor;', 'void main() {',
		'gl_FragColor = u_FragColor;', '}'
	].join('');

	function draw$3(gl, data, options) {

		if (!data) {
			return;
		}

		var program = initShaders(gl, vs_s$1, fs_s$1);

		var a_Position = gl.getAttribLocation(program, 'a_Position');

		var a_PointSize = gl.getAttribLocation(program, 'a_PointSize');

		var uFragColor = gl.getUniformLocation(program, 'u_FragColor');

		//gl.clearColor(0.0, 0.0, 1.0, 1.0);
		gl.clear(gl.COLOR_BUFFER_BIT);

		var halfCanvasWidth = gl.canvas.width / 2;
		var halfCanvasHeight = gl.canvas.height / 2;

		var verticesData = [];
		var count = 0;
		for (var i = 0; i < data.length; i++) {
			var item = data[i].geometry._coordinates;

			var x = (item[0] - halfCanvasWidth) / halfCanvasWidth;
			var y = (halfCanvasHeight - item[1]) / halfCanvasHeight;

			if (x < -1 || x > 1 || y < -1 || y > 1) {
				continue;
			}
			verticesData.push(x, y);
			count++;
		}

		var vertices = new Float32Array(verticesData);
		var n = count; // The number of vertices

		// Create a buffer object
		var vertexBuffer = gl.createBuffer();

		// Bind the buffer object to target
		gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
		// Write date into the buffer object
		gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

		// Assign the buffer object to a_Position variable
		gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);

		// Enable the assignment to a_Position variable
		gl.enableVertexAttribArray(a_Position);

		gl.vertexAttrib1f(a_PointSize, options._size);

		var colored = getColorData(options.fillStyle || 'red');

		gl.uniform4f(uFragColor, colored[0] / 255, colored[1] / 255, colored[2] / 255, colored[3] / 255);
		gl.drawArrays(gl.POINTS, 0, n);
	}

	var point = {
		draw: draw$3
	};

	function earcut(data, holeIndices, dim) {

		dim = dim || 2;

		var hasHoles = holeIndices && holeIndices.length,
			outerLen = hasHoles ? holeIndices[0] * dim : data.length,
			outerNode = linkedList(data, 0, outerLen, dim, true),
			triangles = [];

		if (!outerNode) return triangles;

		var minX, minY, maxX, maxY, x, y, size;

		if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim);

		// if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
		if (data.length > 80 * dim) {
			minX = maxX = data[0];
			minY = maxY = data[1];

			for (var i = dim; i < outerLen; i += dim) {
				x = data[i];
				y = data[i + 1];
				if (x < minX) minX = x;
				if (y < minY) minY = y;
				if (x > maxX) maxX = x;
				if (y > maxY) maxY = y;
			}

			// minX, minY and size are later used to transform coords into integers for z-order calculation
			size = Math.max(maxX - minX, maxY - minY);
		}

		earcutLinked(outerNode, triangles, dim, minX, minY, size);

		return triangles;
	}

	// create a circular doubly linked list from polygon points in the specified winding order
	function linkedList(data, start, end, dim, clockwise) {
		var i, last;

		if (clockwise === signedArea(data, start, end, dim) > 0) {
			for (i = start; i < end; i += dim) {
				last = insertNode(i, data[i], data[i + 1], last);
			}
		} else {
			for (i = end - dim; i >= start; i -= dim) {
				last = insertNode(i, data[i], data[i + 1], last);
			}
		}

		if (last && equals(last, last.next)) {
			removeNode(last);
			last = last.next;
		}

		return last;
	}

	// eliminate colinear or duplicate points
	function filterPoints(start, end) {
		if (!start) return start;
		if (!end) end = start;

		var p = start,
			again;
		do {
			again = false;

			if (!p.steiner && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) {
				removeNode(p);
				p = end = p.prev;
				if (p === p.next) return null;
				again = true;
			} else {
				p = p.next;
			}
		} while (again || p !== end);

		return end;
	}

	// main ear slicing loop which triangulates a polygon (given as a linked list)
	function earcutLinked(ear, triangles, dim, minX, minY, size, pass) {
		if (!ear) return;

		// interlink polygon nodes in z-order
		if (!pass && size) indexCurve(ear, minX, minY, size);

		var stop = ear,
			prev,
			next;

		// iterate through ears, slicing them one by one
		while (ear.prev !== ear.next) {
			prev = ear.prev;
			next = ear.next;

			if (size ? isEarHashed(ear, minX, minY, size) : isEar(ear)) {
				// cut off the triangle
				triangles.push(prev.i / dim);
				triangles.push(ear.i / dim);
				triangles.push(next.i / dim);

				removeNode(ear);

				// skipping the next vertice leads to less sliver triangles
				ear = next.next;
				stop = next.next;

				continue;
			}

			ear = next;

			// if we looped through the whole remaining polygon and can't find any more ears
			if (ear === stop) {
				// try filtering points and slicing again
				if (!pass) {
					earcutLinked(filterPoints(ear), triangles, dim, minX, minY, size, 1);

					// if this didn't work, try curing all small self-intersections locally
				} else if (pass === 1) {
					ear = cureLocalIntersections(ear, triangles, dim);
					earcutLinked(ear, triangles, dim, minX, minY, size, 2);

					// as a last resort, try splitting the remaining polygon into two
				} else if (pass === 2) {
					splitEarcut(ear, triangles, dim, minX, minY, size);
				}

				break;
			}
		}
	}

	// check whether a polygon node forms a valid ear with adjacent nodes
	function isEar(ear) {
		var a = ear.prev,
			b = ear,
			c = ear.next;

		if (area(a, b, c) >= 0) return false; // reflex, can't be an ear

		// now make sure we don't have other points inside the potential ear
		var p = ear.next.next;

		while (p !== ear.prev) {
			if (pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
			p = p.next;
		}

		return true;
	}

	function isEarHashed(ear, minX, minY, size) {
		var a = ear.prev,
			b = ear,
			c = ear.next;

		if (area(a, b, c) >= 0) return false; // reflex, can't be an ear

		// triangle bbox; min & max are calculated like this for speed
		var minTX = a.x < b.x ? a.x < c.x ? a.x : c.x : b.x < c.x ? b.x : c.x,
			minTY = a.y < b.y ? a.y < c.y ? a.y : c.y : b.y < c.y ? b.y : c.y,
			maxTX = a.x > b.x ? a.x > c.x ? a.x : c.x : b.x > c.x ? b.x : c.x,
			maxTY = a.y > b.y ? a.y > c.y ? a.y : c.y : b.y > c.y ? b.y : c.y;

		// z-order range for the current triangle bbox;
		var minZ = zOrder(minTX, minTY, minX, minY, size),
			maxZ = zOrder(maxTX, maxTY, minX, minY, size);

		// first look for points inside the triangle in increasing z-order
		var p = ear.nextZ;

		while (p && p.z <= maxZ) {
			if (p !== ear.prev && p !== ear.next && pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && area(p.prev, p,
					p.next) >= 0) return false;
			p = p.nextZ;
		}

		// then look for points in decreasing z-order
		p = ear.prevZ;

		while (p && p.z >= minZ) {
			if (p !== ear.prev && p !== ear.next && pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && area(p.prev, p,
					p.next) >= 0) return false;
			p = p.prevZ;
		}

		return true;
	}

	// go through all polygon nodes and cure small local self-intersections
	function cureLocalIntersections(start, triangles, dim) {
		var p = start;
		do {
			var a = p.prev,
				b = p.next.next;

			if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) {

				triangles.push(a.i / dim);
				triangles.push(p.i / dim);
				triangles.push(b.i / dim);

				// remove two nodes involved
				removeNode(p);
				removeNode(p.next);

				p = start = b;
			}
			p = p.next;
		} while (p !== start);

		return p;
	}

	// try splitting polygon into two and triangulate them independently
	function splitEarcut(start, triangles, dim, minX, minY, size) {
		// look for a valid diagonal that divides the polygon into two
		var a = start;
		do {
			var b = a.next.next;
			while (b !== a.prev) {
				if (a.i !== b.i && isValidDiagonal(a, b)) {
					// split the polygon in two by the diagonal
					var c = splitPolygon(a, b);

					// filter colinear points around the cuts
					a = filterPoints(a, a.next);
					c = filterPoints(c, c.next);

					// run earcut on each half
					earcutLinked(a, triangles, dim, minX, minY, size);
					earcutLinked(c, triangles, dim, minX, minY, size);
					return;
				}
				b = b.next;
			}
			a = a.next;
		} while (a !== start);
	}

	// link every hole into the outer loop, producing a single-ring polygon without holes
	function eliminateHoles(data, holeIndices, outerNode, dim) {
		var queue = [],
			i,
			len,
			start,
			end,
			list;

		for (i = 0, len = holeIndices.length; i < len; i++) {
			start = holeIndices[i] * dim;
			end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
			list = linkedList(data, start, end, dim, false);
			if (list === list.next) list.steiner = true;
			queue.push(getLeftmost(list));
		}

		queue.sort(compareX);

		// process holes from left to right
		for (i = 0; i < queue.length; i++) {
			eliminateHole(queue[i], outerNode);
			outerNode = filterPoints(outerNode, outerNode.next);
		}

		return outerNode;
	}

	function compareX(a, b) {
		return a.x - b.x;
	}

	// find a bridge between vertices that connects hole with an outer ring and and link it
	function eliminateHole(hole, outerNode) {
		outerNode = findHoleBridge(hole, outerNode);
		if (outerNode) {
			var b = splitPolygon(outerNode, hole);
			filterPoints(b, b.next);
		}
	}

	// David Eberly's algorithm for finding a bridge between hole and outer polygon
	function findHoleBridge(hole, outerNode) {
		var p = outerNode,
			hx = hole.x,
			hy = hole.y,
			qx = -Infinity,
			m;

		// find a segment intersected by a ray from the hole's leftmost point to the left;
		// segment's endpoint with lesser x will be potential connection point
		do {
			if (hy <= p.y && hy >= p.next.y) {
				var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
				if (x <= hx && x > qx) {
					qx = x;
					if (x === hx) {
						if (hy === p.y) return p;
						if (hy === p.next.y) return p.next;
					}
					m = p.x < p.next.x ? p : p.next;
				}
			}
			p = p.next;
		} while (p !== outerNode);

		if (!m) return null;

		if (hx === qx) return m.prev; // hole touches outer segment; pick lower endpoint

		// look for points inside the triangle of hole point, segment intersection and endpoint;
		// if there are no points found, we have a valid connection;
		// otherwise choose the point of the minimum angle with the ray as connection point

		var stop = m,
			mx = m.x,
			my = m.y,
			tanMin = Infinity,
			tan;

		p = m.next;

		while (p !== stop) {
			if (hx >= p.x && p.x >= mx && pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {

				tan = Math.abs(hy - p.y) / (hx - p.x); // tangential

				if ((tan < tanMin || tan === tanMin && p.x > m.x) && locallyInside(p, hole)) {
					m = p;
					tanMin = tan;
				}
			}

			p = p.next;
		}

		return m;
	}

	// interlink polygon nodes in z-order
	function indexCurve(start, minX, minY, size) {
		var p = start;
		do {
			if (p.z === null) p.z = zOrder(p.x, p.y, minX, minY, size);
			p.prevZ = p.prev;
			p.nextZ = p.next;
			p = p.next;
		} while (p !== start);

		p.prevZ.nextZ = null;
		p.prevZ = null;

		sortLinked(p);
	}

	// Simon Tatham's linked list merge sort algorithm
	// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
	function sortLinked(list) {
		var i,
			p,
			q,
			e,
			tail,
			numMerges,
			pSize,
			qSize,
			inSize = 1;

		do {
			p = list;
			list = null;
			tail = null;
			numMerges = 0;

			while (p) {
				numMerges++;
				q = p;
				pSize = 0;
				for (i = 0; i < inSize; i++) {
					pSize++;
					q = q.nextZ;
					if (!q) break;
				}

				qSize = inSize;

				while (pSize > 0 || qSize > 0 && q) {

					if (pSize === 0) {
						e = q;
						q = q.nextZ;
						qSize--;
					} else if (qSize === 0 || !q) {
						e = p;
						p = p.nextZ;
						pSize--;
					} else if (p.z <= q.z) {
						e = p;
						p = p.nextZ;
						pSize--;
					} else {
						e = q;
						q = q.nextZ;
						qSize--;
					}

					if (tail) tail.nextZ = e;
					else list = e;

					e.prevZ = tail;
					tail = e;
				}

				p = q;
			}

			tail.nextZ = null;
			inSize *= 2;
		} while (numMerges > 1);

		return list;
	}

	// z-order of a point given coords and size of the data bounding box
	function zOrder(x, y, minX, minY, size) {
		// coords are transformed into non-negative 15-bit integer range
		x = 32767 * (x - minX) / size;
		y = 32767 * (y - minY) / size;

		x = (x | x << 8) & 0x00FF00FF;
		x = (x | x << 4) & 0x0F0F0F0F;
		x = (x | x << 2) & 0x33333333;
		x = (x | x << 1) & 0x55555555;

		y = (y | y << 8) & 0x00FF00FF;
		y = (y | y << 4) & 0x0F0F0F0F;
		y = (y | y << 2) & 0x33333333;
		y = (y | y << 1) & 0x55555555;

		return x | y << 1;
	}

	// find the leftmost node of a polygon ring
	function getLeftmost(start) {
		var p = start,
			leftmost = start;
		do {
			if (p.x < leftmost.x) leftmost = p;
			p = p.next;
		} while (p !== start);

		return leftmost;
	}

	// check if a point lies within a convex triangle
	function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
		return (cx - px) * (ay - py) - (ax - px) * (cy - py) >= 0 && (ax - px) * (by - py) - (bx - px) * (ay - py) >= 0 &&
			(bx - px) * (cy - py) - (cx - px) * (by - py) >= 0;
	}

	// check if a diagonal between two polygon nodes is valid (lies in polygon interior)
	function isValidDiagonal(a, b) {
		return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) && locallyInside(a, b) && locallyInside(b,
			a) && middleInside(a, b);
	}

	// signed area of a triangle
	function area(p, q, r) {
		return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
	}

	// check if two points are equal
	function equals(p1, p2) {
		return p1.x === p2.x && p1.y === p2.y;
	}

	// check if two segments intersect
	function intersects(p1, q1, p2, q2) {
		if (equals(p1, q1) && equals(p2, q2) || equals(p1, q2) && equals(p2, q1)) return true;
		return area(p1, q1, p2) > 0 !== area(p1, q1, q2) > 0 && area(p2, q2, p1) > 0 !== area(p2, q2, q1) > 0;
	}

	// check if a polygon diagonal intersects any polygon segments
	function intersectsPolygon(a, b) {
		var p = a;
		do {
			if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i && intersects(p, p.next, a, b)) return true;
			p = p.next;
		} while (p !== a);

		return false;
	}

	// check if a polygon diagonal is locally inside the polygon
	function locallyInside(a, b) {
		return area(a.prev, a, a.next) < 0 ? area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 : area(a, b, a.prev) < 0 ||
			area(a, a.next, b) < 0;
	}

	// check if the middle point of a polygon diagonal is inside the polygon
	function middleInside(a, b) {
		var p = a,
			inside = false,
			px = (a.x + b.x) / 2,
			py = (a.y + b.y) / 2;
		do {
			if (p.y > py !== p.next.y > py && px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x) inside = !inside;
			p = p.next;
		} while (p !== a);

		return inside;
	}

	// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
	// if one belongs to the outer ring and another to a hole, it merges it into a single ring
	function splitPolygon(a, b) {
		var a2 = new Node(a.i, a.x, a.y),
			b2 = new Node(b.i, b.x, b.y),
			an = a.next,
			bp = b.prev;

		a.next = b;
		b.prev = a;

		a2.next = an;
		an.prev = a2;

		b2.next = a2;
		a2.prev = b2;

		bp.next = b2;
		b2.prev = bp;

		return b2;
	}

	// create a node and optionally link it with previous one (in a circular doubly linked list)
	function insertNode(i, x, y, last) {
		var p = new Node(i, x, y);

		if (!last) {
			p.prev = p;
			p.next = p;
		} else {
			p.next = last.next;
			p.prev = last;
			last.next.prev = p;
			last.next = p;
		}
		return p;
	}

	function removeNode(p) {
		p.next.prev = p.prev;
		p.prev.next = p.next;

		if (p.prevZ) p.prevZ.nextZ = p.nextZ;
		if (p.nextZ) p.nextZ.prevZ = p.prevZ;
	}

	function Node(i, x, y) {
		// vertice index in coordinates array
		this.i = i;

		// vertex coordinates
		this.x = x;
		this.y = y;

		// previous and next vertice nodes in a polygon ring
		this.prev = null;
		this.next = null;

		// z-order curve value
		this.z = null;

		// previous and next nodes in z-order
		this.prevZ = null;
		this.nextZ = null;

		// indicates whether this is a steiner point
		this.steiner = false;
	}

	// return a percentage difference between the polygon area and its triangulation area;
	// used to verify correctness of triangulation
	earcut.deviation = function(data, holeIndices, dim, triangles) {
		var hasHoles = holeIndices && holeIndices.length;
		var outerLen = hasHoles ? holeIndices[0] * dim : data.length;

		var polygonArea = Math.abs(signedArea(data, 0, outerLen, dim));
		if (hasHoles) {
			for (var i = 0, len = holeIndices.length; i < len; i++) {
				var start = holeIndices[i] * dim;
				var end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
				polygonArea -= Math.abs(signedArea(data, start, end, dim));
			}
		}

		var trianglesArea = 0;
		for (i = 0; i < triangles.length; i += 3) {
			var a = triangles[i] * dim;
			var b = triangles[i + 1] * dim;
			var c = triangles[i + 2] * dim;
			trianglesArea += Math.abs((data[a] - data[c]) * (data[b + 1] - data[a + 1]) - (data[a] - data[b]) * (data[c + 1] -
				data[a + 1]));
		}

		return polygonArea === 0 && trianglesArea === 0 ? 0 : Math.abs((trianglesArea - polygonArea) / polygonArea);
	};

	function signedArea(data, start, end, dim) {
		var sum = 0;
		for (var i = start, j = end - dim; i < end; i += dim) {
			sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
			j = i;
		}
		return sum;
	}

	// turn a polygon in a multi-dimensional array form (e.g. as in GeoJSON) into a form Earcut accepts
	earcut.flatten = function(data) {
		var dim = data[0][0].length,
			result = {
				vertices: [],
				holes: [],
				dimensions: dim
			},
			holeIndex = 0;

		for (var i = 0; i < data.length; i++) {
			for (var j = 0; j < data[i].length; j++) {
				for (var d = 0; d < dim; d++) {
					result.vertices.push(data[i][j][d]);
				}
			}
			if (i > 0) {
				holeIndex += data[i - 1].length;
				result.holes.push(holeIndex);
			}
		}
		return result;
	};

	var vs_s$2 = ['attribute vec4 a_Position;', 'void main() {', 'gl_Position = a_Position;', 'gl_PointSize = 30.0;',
		'}'
	].join('');

	var fs_s$2 = ['precision mediump float;', 'uniform vec4 u_FragColor;', 'void main() {',
		'gl_FragColor = u_FragColor;', '}'
	].join('');

	function draw$4(gl, data, options) {

		if (!data) {
			return;
		}

		// gl.clearColor(0.0, 0.0, 0.0, 1.0);
		gl.clear(gl.COLOR_BUFFER_BIT);
		gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

		var program = initShaders(gl, vs_s$2, fs_s$2);

		gl.enable(gl.BLEND);
		gl.blendFunc(gl.SRC_ALPHA, gl.ONE);

		var halfCanvasWidth = gl.canvas.width / 2;
		var halfCanvasHeight = gl.canvas.height / 2;

		// Bind the buffer object to target
		gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
		gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.createBuffer());

		var a_Position = gl.getAttribLocation(program, 'a_Position');
		// Assign the buffer object to a_Position variable
		gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);

		// Enable the assignment to a_Position variable
		gl.enableVertexAttribArray(a_Position);

		var uFragColor = gl.getUniformLocation(program, 'u_FragColor');

		var colored = getColorData(options.fillStyle || 'red');

		gl.uniform4f(uFragColor, colored[0] / 255, colored[1] / 255, colored[2] / 255, colored[3] / 255);

		gl.lineWidth(options.lineWidth || 1);

		var verticesArr = [];
		var trianglesArr = [];

		var maxSize = 65536;
		var indexOffset = 0;

		for (var i = 0, len = data.length; i < len; i++) {

			var flatten = earcut.flatten(data[i].geometry._coordinates || data[i].geometry.coordinates);
			var vertices = flatten.vertices;
			indexOffset = verticesArr.length / 2;
			for (var j = 0; j < vertices.length; j += 2) {
				vertices[j] = (vertices[j] - halfCanvasWidth) / halfCanvasWidth;
				vertices[j + 1] = (halfCanvasHeight - vertices[j + 1]) / halfCanvasHeight;
			}

			if ((verticesArr.length + vertices.length) / 2 > maxSize) {
				gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verticesArr), gl.STATIC_DRAW);
				gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(trianglesArr), gl.STATIC_DRAW);
				gl.drawElements(gl.TRIANGLES, trianglesArr.length, gl.UNSIGNED_SHORT, 0);
				verticesArr.length = 0;
				trianglesArr.length = 0;
				indexOffset = 0;
			}

			for (var j = 0; j < vertices.length; j++) {
				verticesArr.push(vertices[j]);
			}

			var triangles = earcut(vertices, flatten.holes, flatten.dimensions);
			for (var j = 0; j < triangles.length; j++) {
				trianglesArr.push(triangles[j] + indexOffset);
			}
		}

		gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verticesArr), gl.STATIC_DRAW);
		gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(trianglesArr), gl.STATIC_DRAW);
		gl.drawElements(gl.TRIANGLES, trianglesArr.length, gl.UNSIGNED_SHORT, 0);

		gl.bindBuffer(gl.ARRAY_BUFFER, null);
		gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
	}

	var polygon = {
		draw: draw$4
	};

	/**
	 * @author kyle / http://nikai.us/
	 */
	var webglDrawSimple = {
		draw: function draw(gl, dataSet, options) {
			var data = dataSet instanceof DataSet ? dataSet.get() : dataSet;
			if (data.length > 0) {
				if (data[0].geometry.type == "LineString") {
					line.draw(gl, data, options);
				} else if (data[0].geometry.type == "Polygon" || data[0].geometry.type == "MultiPolygon") {
					polygon.draw(gl, data, options);
				} else {
					point.draw(gl, data, options);
				}
			}
		}
	};

	/**
	 * 根据弧线的坐标节点数组
	 */
	function getCurvePoints(points, options) {
		options = options || {};
		var curvePoints = [];
		for (var i = 0; i < points.length - 1; i++) {
			var p = getCurveByTwoPoints(points[i], points[i + 1], options.count);
			if (p && p.length > 0) {
				curvePoints = curvePoints.concat(p);
			}
		}
		return curvePoints;
	}

	/**
	 * 根据两点获取曲线坐标点数组
	 * @param Point 起点
	 * @param Point 终点
	 */
	function getCurveByTwoPoints(obj1, obj2, count) {
		if (!obj1 || !obj2) {
			return null;
		}

		var B1 = function B1(x) {
			return 1 - 2 * x + x * x;
		};
		var B2 = function B2(x) {
			return 2 * x - 2 * x * x;
		};
		var B3 = function B3(x) {
			return x * x;
		};

		var curveCoordinates = [];

		var count = count || 40; // 曲线是由一些小的线段组成的，这个表示这个曲线所有到的折线的个数
		var isFuture = false;
		var t, h, h2, lat3, lng3, j, t2;
		var LnArray = [];
		var i = 0;
		var inc = 0;

		if (typeof obj2 == "undefined") {
			if (typeof curveCoordinates != "undefined") {
				curveCoordinates = [];
			}
			return;
		}

		var lat1 = parseFloat(obj1.lat);
		var lat2 = parseFloat(obj2.lat);
		var lng1 = parseFloat(obj1.lng);
		var lng2 = parseFloat(obj2.lng);

		// 计算曲线角度的方法
		if (lng2 > lng1) {
			if (parseFloat(lng2 - lng1) > 180) {
				if (lng1 < 0) {
					lng1 = parseFloat(180 + 180 + lng1);
					lng2 = parseFloat(180 + 180 + lng2);
				}
			}
		}
		// 此时纠正了 lng1 lng2
		j = 0;
		t2 = 0;
		// 纬度相同
		if (lat2 == lat1) {
			t = 0;
			h = lng1 - lng2;
			// 经度相同
		} else if (lng2 == lng1) {
			t = Math.PI / 2;
			h = lat1 - lat2;
		} else {
			t = Math.atan((lat2 - lat1) / (lng2 - lng1));
			h = (lat2 - lat1) / Math.sin(t);
		}
		if (t2 == 0) {
			t2 = t + Math.PI / 5;
		}
		h2 = h / 2;
		lng3 = h2 * Math.cos(t2) + lng1;
		lat3 = h2 * Math.sin(t2) + lat1;

		for (i = 0; i < count + 1; i++) {
			var x = lng1 * B1(inc) + lng3 * B2(inc) + lng2 * B3(inc);
			var y = lat1 * B1(inc) + lat3 * B2(inc) + lat2 * B3(inc);
			var lng1_src = obj1.lng;
			var lng2_src = obj2.lng;

			curveCoordinates.push([lng1_src < 0 && lng2_src > 0 ? x - 360 : x, y]);
			inc = inc + 1 / count;
		}
		return curveCoordinates;
	}

	var curve = {
		getPoints: getCurvePoints
	};

	/* 
	FDEB algorithm implementation [www.win.tue.nl/~dholten/papers/forcebundles_eurovis.pdf].

	Author:  (github.com/upphiminn)
	2013

	*/

	var ForceEdgeBundling = function ForceEdgeBundling() {
		var data_nodes = {},
			// {'nodeid':{'x':,'y':},..}
			data_edges = [],
			// [{'source':'nodeid1', 'target':'nodeid2'},..]
			compatibility_list_for_edge = [],
			subdivision_points_for_edge = [],
			K = 0.1,
			// global bundling constant controling edge stiffness
			S_initial = 0.1,
			// init. distance to move points
			P_initial = 1,
			// init. subdivision number
			P_rate = 2,
			// subdivision rate increase
			C = 6,
			// number of cycles to perform
			I_initial = 70,
			// init. number of iterations for cycle
			I_rate = 0.6666667,
			// rate at which iteration number decreases i.e. 2/3
			compatibility_threshold = 0.6,
			invers_quadratic_mode = false,
			eps = 1e-8;

		/*** Geometry Helper Methods ***/
		function vector_dot_product(p, q) {
			return p.x * q.x + p.y * q.y;
		}

		function edge_as_vector(P) {
			return {
				'x': data_nodes[P.target].x - data_nodes[P.source].x,
				'y': data_nodes[P.target].y - data_nodes[P.source].y
			};
		}

		function edge_length(e) {
			return Math.sqrt(Math.pow(data_nodes[e.source].x - data_nodes[e.target].x, 2) + Math.pow(data_nodes[e.source].y -
				data_nodes[e.target].y, 2));
		}

		function custom_edge_length(e) {
			return Math.sqrt(Math.pow(e.source.x - e.target.x, 2) + Math.pow(e.source.y - e.target.y, 2));
		}

		function edge_midpoint(e) {
			var middle_x = (data_nodes[e.source].x + data_nodes[e.target].x) / 2.0;
			var middle_y = (data_nodes[e.source].y + data_nodes[e.target].y) / 2.0;
			return {
				'x': middle_x,
				'y': middle_y
			};
		}

		function compute_divided_edge_length(e_idx) {
			var length = 0;
			for (var i = 1; i < subdivision_points_for_edge[e_idx].length; i++) {
				var segment_length = euclidean_distance(subdivision_points_for_edge[e_idx][i], subdivision_points_for_edge[
					e_idx][i - 1]);
				length += segment_length;
			}
			return length;
		}

		function euclidean_distance(p, q) {
			return Math.sqrt(Math.pow(p.x - q.x, 2) + Math.pow(p.y - q.y, 2));
		}

		function project_point_on_line(p, Q) {
			var L = Math.sqrt((Q.target.x - Q.source.x) * (Q.target.x - Q.source.x) + (Q.target.y - Q.source.y) * (Q.target.y -
				Q.source.y));
			var r = ((Q.source.y - p.y) * (Q.source.y - Q.target.y) - (Q.source.x - p.x) * (Q.target.x - Q.source.x)) / (L *
				L);

			return {
				'x': Q.source.x + r * (Q.target.x - Q.source.x),
				'y': Q.source.y + r * (Q.target.y - Q.source.y)
			};
		}

		/*** ********************** ***/

		/*** Initialization Methods ***/
		function initialize_edge_subdivisions() {
			for (var i = 0; i < data_edges.length; i++) {
				if (P_initial == 1) subdivision_points_for_edge[i] = []; //0 subdivisions
				else {
					subdivision_points_for_edge[i] = [];
					subdivision_points_for_edge[i].push(data_nodes[data_edges[i].source]);
					subdivision_points_for_edge[i].push(data_nodes[data_edges[i].target]);
				}
			}
		}

		function initialize_compatibility_lists() {
			for (var i = 0; i < data_edges.length; i++) {
				compatibility_list_for_edge[i] = [];
			} //0 compatible edges.
		}

		function filter_self_loops(edgelist) {
			var filtered_edge_list = [];
			for (var e = 0; e < edgelist.length; e++) {
				if (data_nodes[edgelist[e].source].x != data_nodes[edgelist[e].target].x && data_nodes[edgelist[e].source].y !=
					data_nodes[edgelist[e].target].y) {
					//or smaller than eps
					filtered_edge_list.push(edgelist[e]);
				}
			}

			return filtered_edge_list;
		}
		/*** ********************** ***/

		/*** Force Calculation Methods ***/
		function apply_spring_force(e_idx, i, kP) {

			var prev = subdivision_points_for_edge[e_idx][i - 1];
			var next = subdivision_points_for_edge[e_idx][i + 1];
			var crnt = subdivision_points_for_edge[e_idx][i];

			var x = prev.x - crnt.x + next.x - crnt.x;
			var y = prev.y - crnt.y + next.y - crnt.y;

			x *= kP;
			y *= kP;

			return {
				'x': x,
				'y': y
			};
		}

		function apply_electrostatic_force(e_idx, i, S) {
			var sum_of_forces = {
				'x': 0,
				'y': 0
			};
			var compatible_edges_list = compatibility_list_for_edge[e_idx];

			for (var oe = 0; oe < compatible_edges_list.length; oe++) {
				var force = {
					'x': subdivision_points_for_edge[compatible_edges_list[oe]][i].x - subdivision_points_for_edge[e_idx][i].x,
					'y': subdivision_points_for_edge[compatible_edges_list[oe]][i].y - subdivision_points_for_edge[e_idx][i].y
				};

				if (Math.abs(force.x) > eps || Math.abs(force.y) > eps) {

					var diff = 1 / Math.pow(custom_edge_length({
						'source': subdivision_points_for_edge[compatible_edges_list[oe]][i],
						'target': subdivision_points_for_edge[e_idx][i]
					}), 1);

					sum_of_forces.x += force.x * diff;
					sum_of_forces.y += force.y * diff;
				}
			}
			return sum_of_forces;
		}

		function apply_resulting_forces_on_subdivision_points(e_idx, P, S) {
			var kP = K / (edge_length(data_edges[e_idx]) * (P + 1)); // kP=K/|P|(number of segments), where |P| is the initial length of edge P.
			// (length * (num of sub division pts - 1))
			var resulting_forces_for_subdivision_points = [{
				'x': 0,
				'y': 0
			}];
			for (var i = 1; i < P + 1; i++) {
				// exclude initial end points of the edge 0 and P+1
				var resulting_force = {
					'x': 0,
					'y': 0
				};

				var spring_force = apply_spring_force(e_idx, i, kP);
				var electrostatic_force = apply_electrostatic_force(e_idx, i, S);

				resulting_force.x = S * (spring_force.x + electrostatic_force.x);
				resulting_force.y = S * (spring_force.y + electrostatic_force.y);

				resulting_forces_for_subdivision_points.push(resulting_force);
			}
			resulting_forces_for_subdivision_points.push({
				'x': 0,
				'y': 0
			});
			return resulting_forces_for_subdivision_points;
		}
		/*** ********************** ***/

		/*** Edge Division Calculation Methods ***/
		function update_edge_divisions(P) {
			for (var e_idx = 0; e_idx < data_edges.length; e_idx++) {

				if (P == 1) {
					subdivision_points_for_edge[e_idx].push(data_nodes[data_edges[e_idx].source]); // source
					subdivision_points_for_edge[e_idx].push(edge_midpoint(data_edges[e_idx])); // mid point
					subdivision_points_for_edge[e_idx].push(data_nodes[data_edges[e_idx].target]); // target
				} else {

					var divided_edge_length = compute_divided_edge_length(e_idx);
					var segment_length = divided_edge_length / (P + 1);
					var current_segment_length = segment_length;
					var new_subdivision_points = [];
					new_subdivision_points.push(data_nodes[data_edges[e_idx].source]); //source

					for (var i = 1; i < subdivision_points_for_edge[e_idx].length; i++) {
						var old_segment_length = euclidean_distance(subdivision_points_for_edge[e_idx][i],
							subdivision_points_for_edge[e_idx][i - 1]);

						while (old_segment_length > current_segment_length) {
							var percent_position = current_segment_length / old_segment_length;
							var new_subdivision_point_x = subdivision_points_for_edge[e_idx][i - 1].x;
							var new_subdivision_point_y = subdivision_points_for_edge[e_idx][i - 1].y;

							new_subdivision_point_x += percent_position * (subdivision_points_for_edge[e_idx][i].x -
								subdivision_points_for_edge[e_idx][i - 1].x);
							new_subdivision_point_y += percent_position * (subdivision_points_for_edge[e_idx][i].y -
								subdivision_points_for_edge[e_idx][i - 1].y);
							new_subdivision_points.push({
								'x': new_subdivision_point_x,
								'y': new_subdivision_point_y
							});

							old_segment_length -= current_segment_length;
							current_segment_length = segment_length;
						}
						current_segment_length -= old_segment_length;
					}
					new_subdivision_points.push(data_nodes[data_edges[e_idx].target]); //target
					subdivision_points_for_edge[e_idx] = new_subdivision_points;
				}
			}
		}
		/*** ********************** ***/

		/*** Edge compatibility measures ***/
		function angle_compatibility(P, Q) {
			var result = Math.abs(vector_dot_product(edge_as_vector(P), edge_as_vector(Q)) / (edge_length(P) * edge_length(Q)));
			return result;
		}

		function scale_compatibility(P, Q) {
			var lavg = (edge_length(P) + edge_length(Q)) / 2.0;
			var result = 2.0 / (lavg / Math.min(edge_length(P), edge_length(Q)) + Math.max(edge_length(P), edge_length(Q)) /
				lavg);
			return result;
		}

		function position_compatibility(P, Q) {
			var lavg = (edge_length(P) + edge_length(Q)) / 2.0;
			var midP = {
				'x': (data_nodes[P.source].x + data_nodes[P.target].x) / 2.0,
				'y': (data_nodes[P.source].y + data_nodes[P.target].y) / 2.0
			};
			var midQ = {
				'x': (data_nodes[Q.source].x + data_nodes[Q.target].x) / 2.0,
				'y': (data_nodes[Q.source].y + data_nodes[Q.target].y) / 2.0
			};
			var result = lavg / (lavg + euclidean_distance(midP, midQ));
			return result;
		}

		function edge_visibility(P, Q) {
			var I0 = project_point_on_line(data_nodes[Q.source], {
				'source': data_nodes[P.source],
				'target': data_nodes[P.target]
			});
			var I1 = project_point_on_line(data_nodes[Q.target], {
				'source': data_nodes[P.source],
				'target': data_nodes[P.target]
			}); //send acutal edge points positions
			var midI = {
				'x': (I0.x + I1.x) / 2.0,
				'y': (I0.y + I1.y) / 2.0
			};
			var midP = {
				'x': (data_nodes[P.source].x + data_nodes[P.target].x) / 2.0,
				'y': (data_nodes[P.source].y + data_nodes[P.target].y) / 2.0
			};
			var result = Math.max(0, 1 - 2 * euclidean_distance(midP, midI) / euclidean_distance(I0, I1));
			return result;
		}

		function visibility_compatibility(P, Q) {
			return Math.min(edge_visibility(P, Q), edge_visibility(Q, P));
		}

		function compatibility_score(P, Q) {
			var result = angle_compatibility(P, Q) * scale_compatibility(P, Q) * position_compatibility(P, Q) *
				visibility_compatibility(P, Q);

			return result;
		}

		function are_compatible(P, Q) {
			// console.log('compatibility ' + P.source +' - '+ P.target + ' and ' + Q.source +' '+ Q.target);
			return compatibility_score(P, Q) >= compatibility_threshold;
		}

		function compute_compatibility_lists() {
			for (var e = 0; e < data_edges.length - 1; e++) {
				for (var oe = e + 1; oe < data_edges.length; oe++) {
					// don't want any duplicates
					if (e == oe) continue;
					else {
						if (are_compatible(data_edges[e], data_edges[oe])) {
							compatibility_list_for_edge[e].push(oe);
							compatibility_list_for_edge[oe].push(e);
						}
					}
				}
			}
		}

		/*** ************************ ***/

		/*** Main Bundling Loop Methods ***/
		var forcebundle = function forcebundle() {
			var S = S_initial;
			var I = I_initial;
			var P = P_initial;

			initialize_edge_subdivisions();
			initialize_compatibility_lists();
			update_edge_divisions(P);
			compute_compatibility_lists();
			for (var cycle = 0; cycle < C; cycle++) {
				for (var iteration = 0; iteration < I; iteration++) {
					var forces = [];
					for (var edge = 0; edge < data_edges.length; edge++) {
						forces[edge] = apply_resulting_forces_on_subdivision_points(edge, P, S);
					}
					for (var e = 0; e < data_edges.length; e++) {
						for (var i = 0; i < P + 1; i++) {
							subdivision_points_for_edge[e][i].x += forces[e][i].x;
							subdivision_points_for_edge[e][i].y += forces[e][i].y;
						}
					}
				}
				//prepare for next cycle
				S = S / 2;
				P = P * 2;
				I = I_rate * I;

				update_edge_divisions(P);
				// console.log('C' + cycle);
				// console.log('P' + P);
				// console.log('S' + S);
			}
			return subdivision_points_for_edge;
		};
		/*** ************************ ***/

		/*** Getters/Setters Methods ***/
		forcebundle.nodes = function(nl) {
			if (arguments.length == 0) {
				return data_nodes;
			} else {
				data_nodes = nl;
			}
			return forcebundle;
		};

		forcebundle.edges = function(ll) {
			if (arguments.length == 0) {
				return data_edges;
			} else {
				data_edges = filter_self_loops(ll); //remove edges to from to the same point
			}
			return forcebundle;
		};

		forcebundle.bundling_stiffness = function(k) {
			if (arguments.length == 0) {
				return K;
			} else {
				K = k;
			}
			return forcebundle;
		};

		forcebundle.step_size = function(step) {
			if (arguments.length == 0) {
				return S_initial;
			} else {
				S_initial = step;
			}
			return forcebundle;
		};

		forcebundle.cycles = function(c) {
			if (arguments.length == 0) {
				return C;
			} else {
				C = c;
			}
			return forcebundle;
		};

		forcebundle.iterations = function(i) {
			if (arguments.length == 0) {
				return I_initial;
			} else {
				I_initial = i;
			}
			return forcebundle;
		};

		forcebundle.iterations_rate = function(i) {
			if (arguments.length == 0) {
				return I_rate;
			} else {
				I_rate = i;
			}
			return forcebundle;
		};

		forcebundle.subdivision_points_seed = function(p) {
			if (arguments.length == 0) {
				return P;
			} else {
				P = p;
			}
			return forcebundle;
		};

		forcebundle.subdivision_rate = function(r) {
			if (arguments.length == 0) {
				return P_rate;
			} else {
				P_rate = r;
			}
			return forcebundle;
		};

		forcebundle.compatbility_threshold = function(t) {
			if (arguments.length == 0) {
				return compatbility_threshold;
			} else {
				compatibility_threshold = t;
			}
			return forcebundle;
		};

		/*** ************************ ***/

		return forcebundle;
	};

	/**
	 * @author kyle / http://nikai.us/
	 */

	/**
	 * Category
	 * @param {Object} splitList:
	 *   { 
	 *       other: 1,
	 *       1: 2,
	 *       2: 3,
	 *       3: 4,
	 *       4: 5,
	 *       5: 6,
	 *       6: 7
	 *   }
	 */
	function Category(splitList) {
		this.splitList = splitList || {
			other: 1
		};
	}

	Category.prototype.get = function(count) {

		var splitList = this.splitList;

		var value = splitList['other'];

		for (var i in splitList) {
			if (count == i) {
				value = splitList[i];
				break;
			}
		}

		return value;
	};

	/**
	 * 根据DataSet自动生成对应的splitList
	 */
	Category.prototype.generateByDataSet = function(dataSet, color) {
		var colors = color || ['rgba(255, 255, 0, 0.8)', 'rgba(253, 98, 104, 0.8)', 'rgba(255, 146, 149, 0.8)',
			'rgba(255, 241, 193, 0.8)', 'rgba(110, 176, 253, 0.8)', 'rgba(52, 139, 251, 0.8)', 'rgba(17, 102, 252, 0.8)'
		];
		var data = dataSet.get();
		this.splitList = {};
		var count = 0;
		for (var i = 0; i < data.length; i++) {
			if (this.splitList[data[i].count] === undefined) {
				this.splitList[data[i].count] = colors[count];
				count++;
			}
			if (count >= colors.length - 1) {
				break;
			}
		}

		this.splitList['other'] = colors[colors.length - 1];
	};

	Category.prototype.getLegend = function(options) {
		var splitList = this.splitList;
		var container = document.createElement('div');
		container.style.cssText = "background:#fff; padding: 5px; border: 1px solid #ccc;";
		var html = '';
		for (var key in splitList) {
			html += '<div style="line-height: 19px;" value="' + key +
				'"><span style="vertical-align: -2px; display: inline-block; width: 30px;height: 19px;background:' + splitList[
					key] + ';"></span><span style="margin-left: 3px;">' + key + '<span></div>';
		}
		container.innerHTML = html;
		return container;
	};

	/**
	 * @author kyle / http://nikai.us/
	 */

	/**
	 * Choropleth
	 * @param {Object} splitList:
	 *       [
	 *           {
	 *               start: 0,
	 *               end: 2,
	 *               value: randomColor()
	 *           },{
	 *               start: 2,
	 *               end: 4,
	 *               value: randomColor()
	 *           },{
	 *               start: 4,
	 *               value: randomColor()
	 *           }
	 *       ];
	 *
	 */
	function Choropleth(splitList) {
		this.splitList = splitList || [{
			start: 0,
			value: 'red'
		}];
	}

	Choropleth.prototype.get = function(count) {
		var splitList = this.splitList;

		var value = false;

		for (var i = 0; i < splitList.length; i++) {
			if ((splitList[i].start === undefined || splitList[i].start !== undefined && count >= splitList[i].start) && (
					splitList[i].end === undefined || splitList[i].end !== undefined && count < splitList[i].end)) {
				value = splitList[i].value;
				break;
			}
		}

		return value;
	};

	/**
	 * 根据DataSet自动生成对应的splitList
	 */
	Choropleth.prototype.generateByDataSet = function(dataSet) {

		var min = dataSet.getMin('count');
		var max = dataSet.getMax('count');

		this.generateByMinMax(min, max);
	};

	/**
	 * 根据DataSet自动生成对应的splitList
	 */
	Choropleth.prototype.generateByMinMax = function(min, max) {
		var colors = ['rgba(255, 255, 0, 0.8)', 'rgba(253, 98, 104, 0.8)', 'rgba(255, 146, 149, 0.8)',
			'rgba(255, 241, 193, 0.8)', 'rgba(110, 176, 253, 0.8)', 'rgba(52, 139, 251, 0.8)', 'rgba(17, 102, 252, 0.8)'
		];
		var splitNum = Number((max - min) / 7);
		// console.log(splitNum)
		max = Number(max);
		var index = Number(min);
		this.splitList = [];
		var count = 0;

		while (index < max) {
			this.splitList.push({
				start: index,
				end: index + splitNum,
				value: colors[count]
			});
			count++;
			index += splitNum;
			// console.log(index, max)
		}
		// console.log('splitNum')
	};

	Choropleth.prototype.getLegend = function(options) {
		var splitList = this.splitList;
	};

	/**
	 * @author Mofei<http://www.zhuwenlong.com>
	 */

	var MapHelper = function() {
		function MapHelper(id, type, opt) {
			classCallCheck(this, MapHelper);

			if (!id || !type) {
				console.warn('id 和 type 为必填项');
				return false;
			}

			if (type == 'baidu') {
				if (!BMap) {
					console.warn('请先引入百度地图JS API');
					return false;
				}
			} else {
				console.warn('暂不支持你的地图类型');
			}
			this.type = type;
			var center = opt && opt.center ? opt.center : [106.962497, 38.208726];
			var zoom = opt && opt.zoom ? opt.zoom : 5;
			var map = this.map = new BMap.Map(id, {
				enableMapClick: false
			});
			map.centerAndZoom(new BMap.Point(center[0], center[1]), zoom);
			map.enableScrollWheelZoom(true);

			map.setMapStyle({
				style: 'light'
			});
		}

		createClass(MapHelper, [{
			key: 'addLayer',
			value: function addLayer(datas, options) {
				if (this.type == 'baidu') {
					return new mapv.baiduMapLayer(this.map, dataSet, options);
				}
			}
		}, {
			key: 'getMap',
			value: function getMap() {
				return this.map;
			}
		}]);
		return MapHelper;
	}();

	/**
	 * 一直覆盖在当前地图视野的Canvas对象
	 *
	 * @author nikai (@胖嘟嘟的骨头, nikai@baidu.com)
	 *
	 * @param 
	 * {
	 *     map 地图实例对象
	 * }
	 */

	function CanvasLayer(options) {
		this.options = options || {};
		this.paneName = this.options.paneName || 'mapPane';
		this.context = this.options.context || '2d';
		this.zIndex = this.options.zIndex || 0;
		this.mixBlendMode = this.options.mixBlendMode || null;
		this.enableMassClear = this.options.enableMassClear;
		this._map = options.map;
		this._lastDrawTime = null;
		this.show();
	}

	var global$3 = typeof window === 'undefined' ? {} : window;

	if (global$3.BMap) {

		CanvasLayer.prototype = new BMap.Overlay();

		CanvasLayer.prototype.initialize = function(map) {
			this._map = map;
			var canvas = this.canvas = document.createElement("canvas");
			canvas.style.cssText = "position:absolute;" + "left:0;" + "top:0;" + "z-index:" + this.zIndex +
				";user-select:none;";
			canvas.style.mixBlendMode = this.mixBlendMode;
			this.adjustSize();
			map.getPanes()[this.paneName].appendChild(canvas);
			var that = this;
			map.addEventListener('resize', function() {
				that.adjustSize();
				that._draw();
			});
			/*
			map.addEventListener('moving', function() {
			    that._draw();
			});
			*/
			return this.canvas;
		};

		CanvasLayer.prototype.adjustSize = function() {
			var size = this._map.getSize();
			var canvas = this.canvas;

			var devicePixelRatio = this.devicePixelRatio = global$3.devicePixelRatio || 1;

			canvas.width = size.width * devicePixelRatio;
			canvas.height = size.height * devicePixelRatio;
			if (this.context == '2d') {
				canvas.getContext(this.context).scale(devicePixelRatio, devicePixelRatio);
			}

			canvas.style.width = size.width + "px";
			canvas.style.height = size.height + "px";
		};

		CanvasLayer.prototype.draw = function() {
			var self = this;
			clearTimeout(self.timeoutID);
			self.timeoutID = setTimeout(function() {
				self._draw();
			}, 15);
		};

		CanvasLayer.prototype._draw = function() {
			var map = this._map;
			var size = map.getSize();
			var center = map.getCenter();
			if (center) {
				var pixel = map.pointToOverlayPixel(center);
				this.canvas.style.left = pixel.x - size.width / 2 + 'px';
				this.canvas.style.top = pixel.y - size.height / 2 + 'px';
				this.dispatchEvent('draw');
				this.options.update && this.options.update.call(this);
			}
		};

		CanvasLayer.prototype.getContainer = function() {
			return this.canvas;
		};

		CanvasLayer.prototype.show = function() {
			if (!this.canvas) {
				this._map.addOverlay(this);
			}
			this.canvas.style.display = "block";
		};

		CanvasLayer.prototype.hide = function() {
			this.canvas.style.display = "none";
			//this._map.removeOverlay(this);
		};

		CanvasLayer.prototype.setZIndex = function(zIndex) {
			this.zIndex = zIndex;
			this.canvas.style.zIndex = this.zIndex;
		};

		CanvasLayer.prototype.getZIndex = function() {
			return this.zIndex;
		};
	}

	/**
	 * Tween.js - Licensed under the MIT license
	 * https://github.com/tweenjs/tween.js
	 * ----------------------------------------------
	 *
	 * See https://github.com/tweenjs/tween.js/graphs/contributors for the full list of contributors.
	 * Thank you all, you're awesome!
	 */

	var TWEEN = TWEEN || function() {

		var _tweens = [];

		return {

			getAll: function getAll() {

				return _tweens;
			},

			removeAll: function removeAll() {

				_tweens = [];
			},

			add: function add(tween) {

				_tweens.push(tween);
			},

			remove: function remove(tween) {

				var i = _tweens.indexOf(tween);

				if (i !== -1) {
					_tweens.splice(i, 1);
				}
			},

			update: function update(time, preserve) {

				if (_tweens.length === 0) {
					return false;
				}

				var i = 0;

				time = time !== undefined ? time : TWEEN.now();

				while (i < _tweens.length) {

					if (_tweens[i].update(time) || preserve) {
						i++;
					} else {
						_tweens.splice(i, 1);
					}
				}

				return true;
			}
		};
	}();

	// Include a performance.now polyfill.
	// In node.js, use process.hrtime.
	if (typeof window === 'undefined' && typeof process !== 'undefined') {
		TWEEN.now = function() {
			var time = process.hrtime();

			// Convert [seconds, nanoseconds] to milliseconds.
			return time[0] * 1000 + time[1] / 1000000;
		};
	}
	// In a browser, use window.performance.now if it is available.
	else if (typeof window !== 'undefined' && window.performance !== undefined && window.performance.now !== undefined) {
		// This must be bound, because directly assigning this function
		// leads to an invocation exception in Chrome.
		TWEEN.now = window.performance.now.bind(window.performance);
	}
	// Use Date.now if it is available.
	else if (Date.now !== undefined) {
		TWEEN.now = Date.now;
	}
	// Otherwise, use 'new Date().getTime()'.
	else {
		TWEEN.now = function() {
			return new Date().getTime();
		};
	}

	TWEEN.Tween = function(object) {

		var _object = object;
		var _valuesStart = {};
		var _valuesEnd = {};
		var _valuesStartRepeat = {};
		var _duration = 1000;
		var _repeat = 0;
		var _repeatDelayTime;
		var _yoyo = false;
		var _isPlaying = false;
		var _reversed = false;
		var _delayTime = 0;
		var _startTime = null;
		var _easingFunction = TWEEN.Easing.Linear.None;
		var _interpolationFunction = TWEEN.Interpolation.Linear;
		var _chainedTweens = [];
		var _onStartCallback = null;
		var _onStartCallbackFired = false;
		var _onUpdateCallback = null;
		var _onCompleteCallback = null;
		var _onStopCallback = null;

		this.to = function(properties, duration) {

			_valuesEnd = properties;

			if (duration !== undefined) {
				_duration = duration;
			}

			return this;
		};

		this.start = function(time) {

			TWEEN.add(this);

			_isPlaying = true;

			_onStartCallbackFired = false;

			_startTime = time !== undefined ? time : TWEEN.now();
			_startTime += _delayTime;

			for (var property in _valuesEnd) {

				// Check if an Array was provided as property value
				if (_valuesEnd[property] instanceof Array) {

					if (_valuesEnd[property].length === 0) {
						continue;
					}

					// Create a local copy of the Array with the start value at the front
					_valuesEnd[property] = [_object[property]].concat(_valuesEnd[property]);
				}

				// If `to()` specifies a property that doesn't exist in the source object,
				// we should not set that property in the object
				if (_object[property] === undefined) {
					continue;
				}

				// Save the starting value.
				_valuesStart[property] = _object[property];

				if (_valuesStart[property] instanceof Array === false) {
					_valuesStart[property] *= 1.0; // Ensures we're using numbers, not strings
				}

				_valuesStartRepeat[property] = _valuesStart[property] || 0;
			}

			return this;
		};

		this.stop = function() {

			if (!_isPlaying) {
				return this;
			}

			TWEEN.remove(this);
			_isPlaying = false;

			if (_onStopCallback !== null) {
				_onStopCallback.call(_object, _object);
			}

			this.stopChainedTweens();
			return this;
		};

		this.end = function() {

			this.update(_startTime + _duration);
			return this;
		};

		this.stopChainedTweens = function() {

			for (var i = 0, numChainedTweens = _chainedTweens.length; i < numChainedTweens; i++) {
				_chainedTweens[i].stop();
			}
		};

		this.delay = function(amount) {

			_delayTime = amount;
			return this;
		};

		this.repeat = function(times) {

			_repeat = times;
			return this;
		};

		this.repeatDelay = function(amount) {

			_repeatDelayTime = amount;
			return this;
		};

		this.yoyo = function(yoyo) {

			_yoyo = yoyo;
			return this;
		};

		this.easing = function(easing) {

			_easingFunction = easing;
			return this;
		};

		this.interpolation = function(interpolation) {

			_interpolationFunction = interpolation;
			return this;
		};

		this.chain = function() {

			_chainedTweens = arguments;
			return this;
		};

		this.onStart = function(callback) {

			_onStartCallback = callback;
			return this;
		};

		this.onUpdate = function(callback) {

			_onUpdateCallback = callback;
			return this;
		};

		this.onComplete = function(callback) {

			_onCompleteCallback = callback;
			return this;
		};

		this.onStop = function(callback) {

			_onStopCallback = callback;
			return this;
		};

		this.update = function(time) {

			var property;
			var elapsed;
			var value;

			if (time < _startTime) {
				return true;
			}

			if (_onStartCallbackFired === false) {

				if (_onStartCallback !== null) {
					_onStartCallback.call(_object, _object);
				}

				_onStartCallbackFired = true;
			}

			elapsed = (time - _startTime) / _duration;
			elapsed = elapsed > 1 ? 1 : elapsed;

			value = _easingFunction(elapsed);

			for (property in _valuesEnd) {

				// Don't update properties that do not exist in the source object
				if (_valuesStart[property] === undefined) {
					continue;
				}

				var start = _valuesStart[property] || 0;
				var end = _valuesEnd[property];

				if (end instanceof Array) {

					_object[property] = _interpolationFunction(end, value);
				} else {

					// Parses relative end values with start as base (e.g.: +10, -3)
					if (typeof end === 'string') {

						if (end.charAt(0) === '+' || end.charAt(0) === '-') {
							end = start + parseFloat(end);
						} else {
							end = parseFloat(end);
						}
					}

					// Protect against non numeric properties.
					if (typeof end === 'number') {
						_object[property] = start + (end - start) * value;
					}
				}
			}

			if (_onUpdateCallback !== null) {
				_onUpdateCallback.call(_object, value);
			}

			if (elapsed === 1) {

				if (_repeat > 0) {

					if (isFinite(_repeat)) {
						_repeat--;
					}

					// Reassign starting values, restart by making startTime = now
					for (property in _valuesStartRepeat) {

						if (typeof _valuesEnd[property] === 'string') {
							_valuesStartRepeat[property] = _valuesStartRepeat[property] + parseFloat(_valuesEnd[property]);
						}

						if (_yoyo) {
							var tmp = _valuesStartRepeat[property];

							_valuesStartRepeat[property] = _valuesEnd[property];
							_valuesEnd[property] = tmp;
						}

						_valuesStart[property] = _valuesStartRepeat[property];
					}

					if (_yoyo) {
						_reversed = !_reversed;
					}

					if (_repeatDelayTime !== undefined) {
						_startTime = time + _repeatDelayTime;
					} else {
						_startTime = time + _delayTime;
					}

					return true;
				} else {

					if (_onCompleteCallback !== null) {

						_onCompleteCallback.call(_object, _object);
					}

					for (var i = 0, numChainedTweens = _chainedTweens.length; i < numChainedTweens; i++) {
						// Make the chained tweens start exactly at the time they should,
						// even if the `update()` method was called way past the duration of the tween
						_chainedTweens[i].start(_startTime + _duration);
					}

					return false;
				}
			}

			return true;
		};
	};

	TWEEN.Easing = {

		Linear: {

			None: function None(k) {

				return k;
			}

		},

		Quadratic: {

			In: function In(k) {

				return k * k;
			},

			Out: function Out(k) {

				return k * (2 - k);
			},

			InOut: function InOut(k) {

				if ((k *= 2) < 1) {
					return 0.5 * k * k;
				}

				return -0.5 * (--k * (k - 2) - 1);
			}

		},

		Cubic: {

			In: function In(k) {

				return k * k * k;
			},

			Out: function Out(k) {

				return --k * k * k + 1;
			},

			InOut: function InOut(k) {

				if ((k *= 2) < 1) {
					return 0.5 * k * k * k;
				}

				return 0.5 * ((k -= 2) * k * k + 2);
			}

		},

		Quartic: {

			In: function In(k) {

				return k * k * k * k;
			},

			Out: function Out(k) {

				return 1 - --k * k * k * k;
			},

			InOut: function InOut(k) {

				if ((k *= 2) < 1) {
					return 0.5 * k * k * k * k;
				}

				return -0.5 * ((k -= 2) * k * k * k - 2);
			}

		},

		Quintic: {

			In: function In(k) {

				return k * k * k * k * k;
			},

			Out: function Out(k) {

				return --k * k * k * k * k + 1;
			},

			InOut: function InOut(k) {

				if ((k *= 2) < 1) {
					return 0.5 * k * k * k * k * k;
				}

				return 0.5 * ((k -= 2) * k * k * k * k + 2);
			}

		},

		Sinusoidal: {

			In: function In(k) {

				return 1 - Math.cos(k * Math.PI / 2);
			},

			Out: function Out(k) {

				return Math.sin(k * Math.PI / 2);
			},

			InOut: function InOut(k) {

				return 0.5 * (1 - Math.cos(Math.PI * k));
			}

		},

		Exponential: {

			In: function In(k) {

				return k === 0 ? 0 : Math.pow(1024, k - 1);
			},

			Out: function Out(k) {

				return k === 1 ? 1 : 1 - Math.pow(2, -10 * k);
			},

			InOut: function InOut(k) {

				if (k === 0) {
					return 0;
				}

				if (k === 1) {
					return 1;
				}

				if ((k *= 2) < 1) {
					return 0.5 * Math.pow(1024, k - 1);
				}

				return 0.5 * (-Math.pow(2, -10 * (k - 1)) + 2);
			}

		},

		Circular: {

			In: function In(k) {

				return 1 - Math.sqrt(1 - k * k);
			},

			Out: function Out(k) {

				return Math.sqrt(1 - --k * k);
			},

			InOut: function InOut(k) {

				if ((k *= 2) < 1) {
					return -0.5 * (Math.sqrt(1 - k * k) - 1);
				}

				return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1);
			}

		},

		Elastic: {

			In: function In(k) {

				if (k === 0) {
					return 0;
				}

				if (k === 1) {
					return 1;
				}

				return -Math.pow(2, 10 * (k - 1)) * Math.sin((k - 1.1) * 5 * Math.PI);
			},

			Out: function Out(k) {

				if (k === 0) {
					return 0;
				}

				if (k === 1) {
					return 1;
				}

				return Math.pow(2, -10 * k) * Math.sin((k - 0.1) * 5 * Math.PI) + 1;
			},

			InOut: function InOut(k) {

				if (k === 0) {
					return 0;
				}

				if (k === 1) {
					return 1;
				}

				k *= 2;

				if (k < 1) {
					return -0.5 * Math.pow(2, 10 * (k - 1)) * Math.sin((k - 1.1) * 5 * Math.PI);
				}

				return 0.5 * Math.pow(2, -10 * (k - 1)) * Math.sin((k - 1.1) * 5 * Math.PI) + 1;
			}

		},

		Back: {

			In: function In(k) {

				var s = 1.70158;

				return k * k * ((s + 1) * k - s);
			},

			Out: function Out(k) {

				var s = 1.70158;

				return --k * k * ((s + 1) * k + s) + 1;
			},

			InOut: function InOut(k) {

				var s = 1.70158 * 1.525;

				if ((k *= 2) < 1) {
					return 0.5 * (k * k * ((s + 1) * k - s));
				}

				return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2);
			}

		},

		Bounce: {

			In: function In(k) {

				return 1 - TWEEN.Easing.Bounce.Out(1 - k);
			},

			Out: function Out(k) {

				if (k < 1 / 2.75) {
					return 7.5625 * k * k;
				} else if (k < 2 / 2.75) {
					return 7.5625 * (k -= 1.5 / 2.75) * k + 0.75;
				} else if (k < 2.5 / 2.75) {
					return 7.5625 * (k -= 2.25 / 2.75) * k + 0.9375;
				} else {
					return 7.5625 * (k -= 2.625 / 2.75) * k + 0.984375;
				}
			},

			InOut: function InOut(k) {

				if (k < 0.5) {
					return TWEEN.Easing.Bounce.In(k * 2) * 0.5;
				}

				return TWEEN.Easing.Bounce.Out(k * 2 - 1) * 0.5 + 0.5;
			}

		}

	};

	TWEEN.Interpolation = {

		Linear: function Linear(v, k) {

			var m = v.length - 1;
			var f = m * k;
			var i = Math.floor(f);
			var fn = TWEEN.Interpolation.Utils.Linear;

			if (k < 0) {
				return fn(v[0], v[1], f);
			}

			if (k > 1) {
				return fn(v[m], v[m - 1], m - f);
			}

			return fn(v[i], v[i + 1 > m ? m : i + 1], f - i);
		},

		Bezier: function Bezier(v, k) {

			var b = 0;
			var n = v.length - 1;
			var pw = Math.pow;
			var bn = TWEEN.Interpolation.Utils.Bernstein;

			for (var i = 0; i <= n; i++) {
				b += pw(1 - k, n - i) * pw(k, i) * v[i] * bn(n, i);
			}

			return b;
		},

		CatmullRom: function CatmullRom(v, k) {

			var m = v.length - 1;
			var f = m * k;
			var i = Math.floor(f);
			var fn = TWEEN.Interpolation.Utils.CatmullRom;

			if (v[0] === v[m]) {

				if (k < 0) {
					i = Math.floor(f = m * (1 + k));
				}

				return fn(v[(i - 1 + m) % m], v[i], v[(i + 1) % m], v[(i + 2) % m], f - i);
			} else {

				if (k < 0) {
					return v[0] - (fn(v[0], v[0], v[1], v[1], -f) - v[0]);
				}

				if (k > 1) {
					return v[m] - (fn(v[m], v[m], v[m - 1], v[m - 1], f - m) - v[m]);
				}

				return fn(v[i ? i - 1 : 0], v[i], v[m < i + 1 ? m : i + 1], v[m < i + 2 ? m : i + 2], f - i);
			}
		},

		Utils: {

			Linear: function Linear(p0, p1, t) {

				return (p1 - p0) * t + p0;
			},

			Bernstein: function Bernstein(n, i) {

				var fc = TWEEN.Interpolation.Utils.Factorial;

				return fc(n) / fc(i) / fc(n - i);
			},

			Factorial: function() {

				var a = [1];

				return function(n) {

					var s = 1;

					if (a[n]) {
						return a[n];
					}

					for (var i = n; i > 1; i--) {
						s *= i;
					}

					a[n] = s;
					return s;
				};
			}(),

			CatmullRom: function CatmullRom(p0, p1, p2, p3, t) {

				var v0 = (p2 - p0) * 0.5;
				var v1 = (p3 - p1) * 0.5;
				var t2 = t * t;
				var t3 = t * t2;

				return (2 * p1 - 2 * p2 + v0 + v1) * t3 + (-3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1;
			}

		}

	};

	/**
	 * 根据2点获取角度
	 * @param Array [123, 23] 点1
	 * @param Array [123, 23] 点2
	 * @return angle 角度,不是弧度
	 */
	function getAngle(start, end) {
		var diff_x = end[0] - start[0];
		var diff_y = end[1] - start[1];
		var deg = 360 * Math.atan(diff_y / diff_x) / (2 * Math.PI);
		if (end[0] < start[0]) {
			deg = deg + 180;
		}
		return deg;
	}

	/**
	 * 绘制沿线箭头
	 * @author kyle / http://nikai.us/
	 */

	var imageCache = {};

	var object = {
		draw: function draw(context, dataSet, options) {
			var imageCacheKey = 'http://huiyan.baidu.com/github/tools/gis-drawing/static/images/direction.png';
			if (options.arrow && options.arrow.url) {
				imageCacheKey = options.arrow.url;
			}

			if (!imageCache[imageCacheKey]) {
				imageCache[imageCacheKey] = null;
			}

			var directionImage = imageCache[imageCacheKey];

			if (!directionImage) {
				var args = Array.prototype.slice.call(arguments);
				var image = new Image();
				image.onload = function() {
					imageCache[imageCacheKey] = image;
					object.draw.apply(null, args);
				};
				image.src = imageCacheKey;
				return;
			}

			var data = dataSet instanceof DataSet ? dataSet.get() : dataSet;

			// console.log('xxxx',options)
			context.save();

			for (var key in options) {
				context[key] = options[key];
			}

			var points = [];
			var preCoordinate = null;
			for (var i = 0, len = data.length; i < len; i++) {

				var item = data[i];

				context.save();

				if (item.fillStyle || item._fillStyle) {
					context.fillStyle = item.fillStyle || item._fillStyle;
				}

				if (item.strokeStyle || item._strokeStyle) {
					context.strokeStyle = item.strokeStyle || item._strokeStyle;
				}

				var type = item.geometry.type;

				context.beginPath();
				if (type === 'LineString') {
					var coordinates = item.geometry._coordinates || item.geometry.coordinates;
					var interval = options.arrow.interval !== undefined ? options.arrow.interval : 1;
					for (var j = 0; j < coordinates.length; j += interval) {
						if (coordinates[j] && coordinates[j + 1]) {
							var coordinate = coordinates[j];

							if (preCoordinate && getDistance(coordinate, preCoordinate) < 30) {
								continue;
							}

							context.save();
							var angle = getAngle(coordinates[j], coordinates[j + 1]);
							context.translate(coordinate[0], coordinate[1]);
							context.rotate(angle * Math.PI / 180);
							context.drawImage(directionImage, -directionImage.width / 2 / 2, -directionImage.height / 2 / 2,
								directionImage.width / 2, directionImage.height / 2);
							context.restore();

							points.push(coordinate);
							preCoordinate = coordinate;
						}
					}
				}

				context.restore();
			}

			context.restore();
		}
	};

	function getDistance(coordinateA, coordinateB) {
		return Math.sqrt(Math.pow(coordinateA[0] - coordinateB[0], 2) + Math.pow(coordinateA[1] - coordinateB[1], 2));
	}

	/**
	 * @author Mofei Zhu<mapv@zhuwenlong.com>
	 * This file is to draw text
	 */

	var drawClip = {
		draw: function draw(context, dataSet, options) {
			var data = dataSet instanceof DataSet ? dataSet.get() : dataSet;
			context.save();

			context.fillStyle = options.fillStyle || 'rgba(0, 0, 0, 0.5)';
			context.fillRect(0, 0, context.canvas.width, context.canvas.height);

			options.multiPolygonDraw = function() {
				context.save();
				context.clip();
				clear(context);
				context.restore();
			};

			for (var i = 0, len = data.length; i < len; i++) {

				context.beginPath();

				pathSimple.drawDataSet(context, [data[i]], options);
				context.save();
				context.clip();
				clear(context);
				context.restore();
			}

			context.restore();
		}
	};

	/**
	 * @author kyle / http://nikai.us/
	 */

	var drawCluster = {
		draw: function draw(context, dataSet, options) {
			context.save();
			var data = dataSet instanceof DataSet ? dataSet.get() : dataSet;

			var pointCountMax;
			var pointCountMin;
			for (var i = 0; i < data.length; i++) {
				var item = data[i];
				if (item.properties && item.properties.cluster) {
					if (pointCountMax === undefined) {
						pointCountMax = item.properties.point_count;
					}
					if (pointCountMin === undefined) {
						pointCountMin = item.properties.point_count;
					}
					pointCountMax = Math.max(pointCountMax, item.properties.point_count);
					pointCountMin = Math.min(pointCountMin, item.properties.point_count);
				}
			}

			var intensity = new Intensity({
				min: pointCountMin,
				max: pointCountMax,
				minSize: options.minSize || 8,
				maxSize: options.maxSize || 30,
				gradient: options.gradient
			});

			for (var i = 0; i < data.length; i++) {
				var item = data[i];
				var coordinates = data[i].geometry._coordinates || data[i].geometry.coordinates;
				context.beginPath();
				if (item.properties && item.properties.cluster) {
					context.arc(coordinates[0], coordinates[1], intensity.getSize(item.properties.point_count), 0, Math.PI * 2);
					context.fillStyle = intensity.getColor(item.properties.point_count);
					context.fill();

					if (options.label && options.label.show !== false) {

						context.fillStyle = options.label.fillStyle || 'white';

						if (options.label.font) {
							context.font = options.label.font;
						}

						if (options.label.shadowColor) {
							context.shadowColor = options.label.shadowColor;
						}

						if (options.label.shadowBlur) {
							context.shadowBlur = options.label.shadowBlur;
						}

						var text = item.properties.point_count;
						var textWidth = context.measureText(text).width;
						context.fillText(text, coordinates[0] + .5 - textWidth / 2, coordinates[1] + .5 + 3);
					}
				} else {
					context.arc(coordinates[0], coordinates[1], options.size || 5, 0, Math.PI * 2);
					context.fillStyle = options.fillStyle || 'red';
					context.fill();
				}
			}
			context.restore();
		}
	};

	/**
	 * @author Mofei Zhu<mapv@zhuwenlong.com>
	 * This file is to draw text
	 */

	var drawText = {
		draw: function draw(context, dataSet, options) {

			var data = dataSet instanceof DataSet ? dataSet.get() : dataSet;
			context.save();

			// set from options
			for (var key in options) {
				context[key] = options[key];
			}

			var rects = [];

			var size = options._size || options.size;
			if (size) {
				context.font = "bold " + size + "px Arial";
			} else {
				size = 12;
			}

			var textKey = options.textKey || 'text';

			if (!options.textAlign) {
				context.textAlign = 'center';
			}

			if (!options.textBaseline) {
				context.textBaseline = 'middle';
			}

			if (options.avoid) {
				// 标注避让
				for (var i = 0, len = data.length; i < len; i++) {

					var offset = data[i].offset || options.offset || {
						x: 0,
						y: 0
					};

					var coordinates = data[i].geometry._coordinates || data[i].geometry.coordinates;
					var x = coordinates[0] + offset.x;
					var y = coordinates[1] + offset.y;
					var text = data[i][textKey];
					var textWidth = context.measureText(text).width;

					// 根据文本宽度和高度调整x，y位置，使得绘制文本时候坐标点在文本中心点，这个计算出的是左上角坐标
					var px = x - textWidth / 2;
					var py = y - size / 2;

					var rect = {
						sw: {
							x: px,
							y: py + size
						},
						ne: {
							x: px + textWidth,
							y: py
						}
					};

					if (!hasOverlay(rects, rect)) {
						rects.push(rect);
						px = px + textWidth / 2;
						py = py + size / 2;
						context.fillStyle = "#F5DEB3";
						context.fillRect(px - (context.measureText(text).width / 2) - 2, py - 6, context.measureText(text).width + 4,
							15);
						context.fillStyle = "#FF0000";
						context.fillText(text, px, py);
					}
				}
			} else {
				for (var i = 0, len = data.length; i < len; i++) {
					var offset = data[i].offset || options.offset || {
						x: 0,
						y: 0
					};
					var coordinates = data[i].geometry._coordinates || data[i].geometry.coordinates;
					var x = coordinates[0] + offset.x;
					var y = coordinates[1] + offset.y;
					var text = data[i][textKey];
					context.fillStyle = "#F5DEB3";
					context.fillRect(x - (context.measureText(text).width / 2) - 2, y - 6, context.measureText(text).width + 4,
						15);
					context.fillStyle = "#FF0000";
					context.fillText(text, x, y);
				}
			}

			context.restore();
		}

		/*
		 *  当前文字区域和已有的文字区域是否有重叠部分
		 */
	};

	function hasOverlay(rects, overlay) {
		for (var i = 0; i < rects.length; i++) {
			if (isRectOverlay(rects[i], overlay)) {
				return true;
			}
		}
		return false;
	}

	//判断2个矩形是否有重叠部分
	function isRectOverlay(rect1, rect2) {
		//minx、miny 2个矩形右下角最小的x和y
		//maxx、maxy 2个矩形左上角最大的x和y
		var minx = Math.min(rect1.ne.x, rect2.ne.x);
		var miny = Math.min(rect1.sw.y, rect2.sw.y);
		var maxx = Math.max(rect1.sw.x, rect2.sw.x);
		var maxy = Math.max(rect1.ne.y, rect2.ne.y);
		if (minx > maxx && miny > maxy) {
			return true;
		}
		return false;
	}

	/**
	 * @author Mofei Zhu<mapv@zhuwenlong.com>
	 * This file is to draw text
	 */

	var drawIcon = {
		draw: function draw(context, dataSet, options) {
			var data = dataSet instanceof DataSet ? dataSet.get() : dataSet;

			context.fillStyle = 'white';
			context.textAlign = 'center';
			context.textBaseline = 'middle';

			var offset = options.offset || {
				x: 0,
				y: 0
			};

			// set from options
			// for (var key in options) {
			//     context[key] = options[key];
			// }
			// console.log(data)
			for (var i = 0, len = data.length; i < len; i++) {

				if (data[i].geometry) {
					var deg = data[i].deg || options.deg;
					var icon = data[i].icon || options.icon;
					var coordinates = data[i].geometry._coordinates || data[i].geometry.coordinates;
					var x = coordinates[0];
					var y = coordinates[1];
					var iRotate = 0;
					if (deg) {
						context.save();
						context.translate(x, y);
						iRotate = deg * Math.PI / 180;
						context.rotate(0);
						context.translate(-x, -y);
					}
					var width = options._width || options.width || icon.width;
					var height = options._height || options.height || icon.height;
					x = x - width / 2 + offset.x;
					y = y - height / 2 + offset.y;
					if (data[i].text) {
						for (var key in options) {
							context[key] = options[key];
						}
					}
					if (options.sx && options.sy && options.swidth && options.sheight && options.width && options.height) {
						if (data[i].text) {
							var rects = [];
							var size = options._size || options.size;
							if (size) {
								context.font = "bold " + size + "px Arial";
							} else {
								size = 12;
							}
							if (!options.textAlign) {
								context.textAlign = 'center';
							}
							if (!options.textBaseline) {
								context.textBaseline = 'middle';
							}
							var offsetText = data[i].offsetText || options.offsetText || {
								x: 0,
								y: 0
							};
							var xText = options.sx + offsetText.x;
							var yText = options.sy + offsetText.y;
							var text = data[i].text;
							context.fillStyle = "#F5DEB3";
							context.fillRect(xText - 2 - (context.measureText(text).width / 2), yText - 6, context.measureText(text).width +
								4, 15);
							context.fillStyle = "#FF0000";
							context.fillText(text, xText, yText);
						}
						context.translate(coordinates[0], coordinates[1]);
						context.rotate(iRotate);
						context.translate(-coordinates[0], -coordinates[1]);
						context.drawImage(icon, options.sx, options.sy, options.swidth, options.sheight, x, y, width, height);
					} else if (options.width && options.height) {
						if (data[i].text) {
							var rects = [];
							var size = options._size || options.size;
							if (size) {
								context.font = "bold " + size + "px Arial";
							} else {
								size = 12;
							}
							if (!options.textAlign) {
								context.textAlign = 'center';
							}
							if (!options.textBaseline) {
								context.textBaseline = 'middle';
							}
							var offsetText = data[i].offsetText || options.offsetText || {
								x: 0,
								y: 0
							};
							var xText = x + offsetText.x;
							var yText = y + offsetText.y;
							var text = data[i].text;
							context.fillStyle = "#F5DEB3";
							context.fillRect(xText - 2 - (context.measureText(text).width / 2), yText - 6, context.measureText(text).width +
								4, 15);
							context.fillStyle = "#FF0000";
							context.fillText(text, xText, yText);
						}
						context.translate(coordinates[0], coordinates[1]);
						context.rotate(iRotate);
						context.translate(-coordinates[0], -coordinates[1]);
						context.drawImage(icon, x, y, width, height);
					} else {
						if (data[i].text) {
							var rects = [];
							var size = options._size || options.size;
							if (size) {
								context.font = "bold " + size + "px Arial";
							} else {
								size = 12;
							}
							if (!options.textAlign) {
								context.textAlign = 'center';
							}
							if (!options.textBaseline) {
								context.textBaseline = 'middle';
							}
							var offsetText = data[i].offsetText || options.offsetText || {
								x: 0,
								y: 0
							};
							var xText = x + offsetText.x;
							var yText = y + offsetText.y;
							var text = data[i].text; //执行这段				
							context.fillStyle = "#F5DEB3";
							context.fillRect(xText - 2 - (context.measureText(text).width / 2), yText - 6, context.measureText(text).width +
								4, 15);
							context.fillStyle = "#FF0000";
							context.fillText(text, xText, yText);
						}
						context.translate(coordinates[0], coordinates[1]);
						context.rotate(iRotate);
						context.translate(-coordinates[0], -coordinates[1]);
						context.drawImage(icon, x, y);
					}

					if (deg) {
						context.restore();
					}
				}
			}
		}
	};

	/**
	 * from https://github.com/mapbox/supercluster
	 */

	function sortKD(ids, coords, nodeSize, left, right, depth) {
		if (right - left <= nodeSize) {
			return;
		}

		var m = left + right >> 1;

		select(ids, coords, m, left, right, depth % 2);

		sortKD(ids, coords, nodeSize, left, m - 1, depth + 1);
		sortKD(ids, coords, nodeSize, m + 1, right, depth + 1);
	}

	function select(ids, coords, k, left, right, inc) {

		while (right > left) {
			if (right - left > 600) {
				var n = right - left + 1;
				var m = k - left + 1;
				var z = Math.log(n);
				var s = 0.5 * Math.exp(2 * z / 3);
				var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
				var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
				var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
				select(ids, coords, k, newLeft, newRight, inc);
			}

			var t = coords[2 * k + inc];
			var i = left;
			var j = right;

			swapItem(ids, coords, left, k);
			if (coords[2 * right + inc] > t) {
				swapItem(ids, coords, left, right);
			}

			while (i < j) {
				swapItem(ids, coords, i, j);
				i++;
				j--;
				while (coords[2 * i + inc] < t) {
					i++;
				}
				while (coords[2 * j + inc] > t) {
					j--;
				}
			}

			if (coords[2 * left + inc] === t) {
				swapItem(ids, coords, left, j);
			} else {
				j++;
				swapItem(ids, coords, j, right);
			}

			if (j <= k) {
				left = j + 1;
			}
			if (k <= j) {
				right = j - 1;
			}
		}
	}

	function swapItem(ids, coords, i, j) {
		swap(ids, i, j);
		swap(coords, 2 * i, 2 * j);
		swap(coords, 2 * i + 1, 2 * j + 1);
	}

	function swap(arr, i, j) {
		var tmp = arr[i];
		arr[i] = arr[j];
		arr[j] = tmp;
	}

	function range(ids, coords, minX, minY, maxX, maxY, nodeSize) {
		var stack = [0, ids.length - 1, 0];
		var result = [];
		var x, y;

		while (stack.length) {
			var axis = stack.pop();
			var right = stack.pop();
			var left = stack.pop();

			if (right - left <= nodeSize) {
				for (var i = left; i <= right; i++) {
					x = coords[2 * i];
					y = coords[2 * i + 1];
					if (x >= minX && x <= maxX && y >= minY && y <= maxY) {
						result.push(ids[i]);
					}
				}
				continue;
			}

			var m = Math.floor((left + right) / 2);

			x = coords[2 * m];
			y = coords[2 * m + 1];

			if (x >= minX && x <= maxX && y >= minY && y <= maxY) {
				result.push(ids[m]);
			}

			var nextAxis = (axis + 1) % 2;

			if (axis === 0 ? minX <= x : minY <= y) {
				stack.push(left);
				stack.push(m - 1);
				stack.push(nextAxis);
			}
			if (axis === 0 ? maxX >= x : maxY >= y) {
				stack.push(m + 1);
				stack.push(right);
				stack.push(nextAxis);
			}
		}

		return result;
	}

	function within(ids, coords, qx, qy, r, nodeSize) {
		var stack = [0, ids.length - 1, 0];
		var result = [];
		var r2 = r * r;

		while (stack.length) {
			var axis = stack.pop();
			var right = stack.pop();
			var left = stack.pop();

			if (right - left <= nodeSize) {
				for (var i = left; i <= right; i++) {
					if (sqDist(coords[2 * i], coords[2 * i + 1], qx, qy) <= r2) {
						result.push(ids[i]);
					}
				}
				continue;
			}

			var m = Math.floor((left + right) / 2);

			var x = coords[2 * m];
			var y = coords[2 * m + 1];

			if (sqDist(x, y, qx, qy) <= r2) {
				result.push(ids[m]);
			}

			var nextAxis = (axis + 1) % 2;

			if (axis === 0 ? qx - r <= x : qy - r <= y) {
				stack.push(left);
				stack.push(m - 1);
				stack.push(nextAxis);
			}
			if (axis === 0 ? qx + r >= x : qy + r >= y) {
				stack.push(m + 1);
				stack.push(right);
				stack.push(nextAxis);
			}
		}

		return result;
	}

	function sqDist(ax, ay, bx, by) {
		var dx = ax - bx;
		var dy = ay - by;
		return dx * dx + dy * dy;
	}

	var defaultGetX = function defaultGetX(p) {
		return p[0];
	};
	var defaultGetY = function defaultGetY(p) {
		return p[1];
	};

	var KDBush = function KDBush(points, getX, getY, nodeSize, ArrayType) {
		if (getX === void 0) getX = defaultGetX;
		if (getY === void 0) getY = defaultGetY;
		if (nodeSize === void 0) nodeSize = 64;
		if (ArrayType === void 0) ArrayType = Float64Array;

		this.nodeSize = nodeSize;
		this.points = points;

		var IndexArrayType = points.length < 65536 ? Uint16Array : Uint32Array;

		var ids = this.ids = new IndexArrayType(points.length);
		var coords = this.coords = new ArrayType(points.length * 2);

		for (var i = 0; i < points.length; i++) {
			ids[i] = i;
			coords[2 * i] = getX(points[i]);
			coords[2 * i + 1] = getY(points[i]);
		}

		sortKD(ids, coords, nodeSize, 0, ids.length - 1, 0);
	};

	KDBush.prototype.range = function range$1(minX, minY, maxX, maxY) {
		return range(this.ids, this.coords, minX, minY, maxX, maxY, this.nodeSize);
	};

	KDBush.prototype.within = function within$1(x, y, r) {
		return within(this.ids, this.coords, x, y, r, this.nodeSize);
	};

	var defaultOptions = {
		minZoom: 0, // min zoom to generate clusters on
		maxZoom: 16, // max zoom level to cluster the points on
		radius: 40, // cluster radius in pixels
		extent: 512, // tile extent (radius is calculated relative to it)
		nodeSize: 64, // size of the KD-tree leaf node, affects performance
		log: false, // whether to log timing info

		// a reduce function for calculating custom cluster properties
		reduce: null, // (accumulated, props) => { accumulated.sum += props.sum; }

		// properties to use for individual points when running the reducer
		map: function map(props) {
			return props;
		} // props => ({sum: props.my_value})
	};

	var Supercluster = function Supercluster(options) {
		this.options = extend(Object.create(defaultOptions), options);
		this.trees = new Array(this.options.maxZoom + 1);
	};

	Supercluster.prototype.load = function load(points) {
		var ref = this.options;
		var log = ref.log;
		var minZoom = ref.minZoom;
		var maxZoom = ref.maxZoom;
		var nodeSize = ref.nodeSize;

		if (log) {}

		var timerId = "prepare " + points.length + " points";
		if (log) {}

		this.points = points;

		// generate a cluster object for each point and index input points into a KD-tree
		var clusters = [];
		for (var i = 0; i < points.length; i++) {
			if (!points[i].geometry) {
				continue;
			}
			clusters.push(createPointCluster(points[i], i));
		}
		this.trees[maxZoom + 1] = new KDBush(clusters, getX, getY, nodeSize, Float32Array);

		if (log) {}

		// cluster points on max zoom, then cluster the results on previous zoom, etc.;
		// results in a cluster hierarchy across zoom levels
		for (var z = maxZoom; z >= minZoom; z--) {
			var now = +Date.now();

			// create a new set of clusters for the zoom and index them with a KD-tree
			clusters = this._cluster(clusters, z);
			this.trees[z] = new KDBush(clusters, getX, getY, nodeSize, Float32Array);

			if (log) {}
		}

		if (log) {}

		return this;
	};

	Supercluster.prototype.getClusters = function getClusters(bbox, zoom) {
		var minLng = ((bbox[0] + 180) % 360 + 360) % 360 - 180;
		var minLat = Math.max(-90, Math.min(90, bbox[1]));
		var maxLng = bbox[2] === 180 ? 180 : ((bbox[2] + 180) % 360 + 360) % 360 - 180;
		var maxLat = Math.max(-90, Math.min(90, bbox[3]));

		if (bbox[2] - bbox[0] >= 360) {
			minLng = -180;
			maxLng = 180;
		} else if (minLng > maxLng) {
			var easternHem = this.getClusters([minLng, minLat, 180, maxLat], zoom);
			var westernHem = this.getClusters([-180, minLat, maxLng, maxLat], zoom);
			return easternHem.concat(westernHem);
		}

		var tree = this.trees[this._limitZoom(zoom)];
		var ids = tree.range(lngX(minLng), latY(maxLat), lngX(maxLng), latY(minLat));
		var clusters = [];
		for (var i = 0, list = ids; i < list.length; i += 1) {
			var id = list[i];

			var c = tree.points[id];
			clusters.push(c.numPoints ? getClusterJSON(c) : this.points[c.index]);
		}
		return clusters;
	};

	Supercluster.prototype.getChildren = function getChildren(clusterId) {
		var originId = clusterId >> 5;
		var originZoom = clusterId % 32;
		var errorMsg = 'No cluster with the specified id.';

		var index = this.trees[originZoom];
		if (!index) {
			throw new Error(errorMsg);
		}

		var origin = index.points[originId];
		if (!origin) {
			throw new Error(errorMsg);
		}

		var r = this.options.radius / (this.options.extent * Math.pow(2, originZoom - 1));
		var ids = index.within(origin.x, origin.y, r);
		var children = [];
		for (var i = 0, list = ids; i < list.length; i += 1) {
			var id = list[i];

			var c = index.points[id];
			if (c.parentId === clusterId) {
				children.push(c.numPoints ? getClusterJSON(c) : this.points[c.index]);
			}
		}

		if (children.length === 0) {
			throw new Error(errorMsg);
		}

		return children;
	};

	Supercluster.prototype.getLeaves = function getLeaves(clusterId, limit, offset) {
		limit = limit || 10;
		offset = offset || 0;

		var leaves = [];
		this._appendLeaves(leaves, clusterId, limit, offset, 0);

		return leaves;
	};

	Supercluster.prototype.getTile = function getTile(z, x, y) {
		var tree = this.trees[this._limitZoom(z)];
		var z2 = Math.pow(2, z);
		var ref = this.options;
		var extent = ref.extent;
		var radius = ref.radius;
		var p = radius / extent;
		var top = (y - p) / z2;
		var bottom = (y + 1 + p) / z2;

		var tile = {
			features: []
		};

		this._addTileFeatures(tree.range((x - p) / z2, top, (x + 1 + p) / z2, bottom), tree.points, x, y, z2, tile);

		if (x === 0) {
			this._addTileFeatures(tree.range(1 - p / z2, top, 1, bottom), tree.points, z2, y, z2, tile);
		}
		if (x === z2 - 1) {
			this._addTileFeatures(tree.range(0, top, p / z2, bottom), tree.points, -1, y, z2, tile);
		}

		return tile.features.length ? tile : null;
	};

	Supercluster.prototype.getClusterExpansionZoom = function getClusterExpansionZoom(clusterId) {
		var clusterZoom = clusterId % 32 - 1;
		while (clusterZoom <= this.options.maxZoom) {
			var children = this.getChildren(clusterId);
			clusterZoom++;
			if (children.length !== 1) {
				break;
			}
			clusterId = children[0].properties.cluster_id;
		}
		return clusterZoom;
	};

	Supercluster.prototype._appendLeaves = function _appendLeaves(result, clusterId, limit, offset, skipped) {
		var children = this.getChildren(clusterId);

		for (var i = 0, list = children; i < list.length; i += 1) {
			var child = list[i];

			var props = child.properties;

			if (props && props.cluster) {
				if (skipped + props.point_count <= offset) {
					// skip the whole cluster
					skipped += props.point_count;
				} else {
					// enter the cluster
					skipped = this._appendLeaves(result, props.cluster_id, limit, offset, skipped);
					// exit the cluster
				}
			} else if (skipped < offset) {
				// skip a single point
				skipped++;
			} else {
				// add a single point
				result.push(child);
			}
			if (result.length === limit) {
				break;
			}
		}

		return skipped;
	};

	Supercluster.prototype._addTileFeatures = function _addTileFeatures(ids, points, x, y, z2, tile) {
		for (var i$1 = 0, list = ids; i$1 < list.length; i$1 += 1) {
			var i = list[i$1];

			var c = points[i];
			var f = {
				type: 1,
				geometry: [
					[Math.round(this.options.extent * (c.x * z2 - x)), Math.round(this.options.extent * (c.y * z2 - y))]
				],
				tags: c.numPoints ? getClusterProperties(c) : this.points[c.index].properties
			};
			var id = c.numPoints ? c.id : this.points[c.index].id;
			if (id !== undefined) {
				f.id = id;
			}
			tile.features.push(f);
		}
	};

	Supercluster.prototype._limitZoom = function _limitZoom(z) {
		return Math.max(this.options.minZoom, Math.min(z, this.options.maxZoom + 1));
	};

	Supercluster.prototype._cluster = function _cluster(points, zoom) {
		var clusters = [];
		var ref = this.options;
		var radius = ref.radius;
		var extent = ref.extent;
		var reduce = ref.reduce;
		var r = radius / (extent * Math.pow(2, zoom));

		// loop through each point
		for (var i = 0; i < points.length; i++) {
			var p = points[i];
			// if we've already visited the point at this zoom level, skip it
			if (p.zoom <= zoom) {
				continue;
			}
			p.zoom = zoom;

			// find all nearby points
			var tree = this.trees[zoom + 1];
			var neighborIds = tree.within(p.x, p.y, r);

			var numPoints = p.numPoints || 1;
			var wx = p.x * numPoints;
			var wy = p.y * numPoints;

			var clusterProperties = reduce && numPoints > 1 ? this._map(p, true) : null;

			// encode both zoom and point index on which the cluster originated
			var id = (i << 5) + (zoom + 1);

			for (var i$1 = 0, list = neighborIds; i$1 < list.length; i$1 += 1) {
				var neighborId = list[i$1];

				var b = tree.points[neighborId];
				// filter out neighbors that are already processed
				if (b.zoom <= zoom) {
					continue;
				}
				b.zoom = zoom; // save the zoom (so it doesn't get processed twice)

				var numPoints2 = b.numPoints || 1;
				wx += b.x * numPoints2; // accumulate coordinates for calculating weighted center
				wy += b.y * numPoints2;

				numPoints += numPoints2;
				b.parentId = id;

				if (reduce) {
					if (!clusterProperties) {
						clusterProperties = this._map(p, true);
					}
					reduce(clusterProperties, this._map(b));
				}
			}

			if (numPoints === 1) {
				clusters.push(p);
			} else {
				p.parentId = id;
				clusters.push(createCluster(wx / numPoints, wy / numPoints, id, numPoints, clusterProperties));
			}
		}

		return clusters;
	};

	Supercluster.prototype._map = function _map(point, clone) {
		if (point.numPoints) {
			return clone ? extend({}, point.properties) : point.properties;
		}
		var original = this.points[point.index].properties;
		var result = this.options.map(original);
		return clone && result === original ? extend({}, result) : result;
	};

	function createCluster(x, y, id, numPoints, properties) {
		return {
			x: x, // weighted cluster center
			y: y,
			zoom: Infinity, // the last zoom the cluster was processed at
			id: id, // encodes index of the first child of the cluster and its zoom level
			parentId: -1, // parent cluster id
			numPoints: numPoints,
			properties: properties
		};
	}

	function createPointCluster(p, id) {
		var ref = p.geometry.coordinates;
		var x = ref[0];
		var y = ref[1];
		return {
			x: lngX(x), // projected point coordinates
			y: latY(y),
			zoom: Infinity, // the last zoom the point was processed at
			index: id, // index of the source feature in the original input array,
			parentId: -1 // parent cluster id
		};
	}

	function getClusterJSON(cluster) {
		return {
			type: 'Feature',
			id: cluster.id,
			properties: getClusterProperties(cluster),
			geometry: {
				type: 'Point',
				coordinates: [xLng(cluster.x), yLat(cluster.y)]
			}
		};
	}

	function getClusterProperties(cluster) {
		var count = cluster.numPoints;
		var abbrev = count >= 10000 ? Math.round(count / 1000) + "k" : count >= 1000 ? Math.round(count / 100) / 10 + "k" :
			count;
		return extend(extend({}, cluster.properties), {
			cluster: true,
			cluster_id: cluster.id,
			point_count: count,
			point_count_abbreviated: abbrev
		});
	}

	// longitude/latitude to spherical mercator in [0..1] range
	function lngX(lng) {
		return lng / 360 + 0.5;
	}

	function latY(lat) {
		var sin = Math.sin(lat * Math.PI / 180);
		var y = 0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI;
		return y < 0 ? 0 : y > 1 ? 1 : y;
	}

	// spherical mercator to longitude/latitude
	function xLng(x) {
		return (x - 0.5) * 360;
	}

	function yLat(y) {
		var y2 = (180 - y * 360) * Math.PI / 180;
		return 360 * Math.atan(Math.exp(y2)) / Math.PI - 90;
	}

	function extend(dest, src) {
		for (var id in src) {
			dest[id] = src[id];
		}
		return dest;
	}

	function getX(p) {
		return p.x;
	}

	function getY(p) {
		return p.y;
	}

	/**
	 * @author kyle / http://nikai.us/
	 */

	if (typeof window !== 'undefined') {
		requestAnimationFrame(animate);
	}

	function animate(time) {
		requestAnimationFrame(animate);
		TWEEN.update(time);
	}

	var BaseLayer = function() {
		function BaseLayer(map, dataSet, options) {
			classCallCheck(this, BaseLayer);

			if (!(dataSet instanceof DataSet)) {
				dataSet = new DataSet(dataSet);
			}

			this.dataSet = dataSet;
			this.map = map;

			if (options.draw === 'cluster' && !this.supercluster) {
				this.supercluster = new Supercluster({
					maxZoom: options.maxZoom || 19,
					radius: options.clusterRadius || 100
				});
				this.supercluster.load(dataSet.get());
				this.clusterDataSet = new DataSet();
			}
		}

		createClass(BaseLayer, [{
			key: "getDefaultContextConfig",
			value: function getDefaultContextConfig() {
				return {
					globalAlpha: 1,
					globalCompositeOperation: 'source-over',
					imageSmoothingEnabled: true,
					strokeStyle: '#000000',
					fillStyle: '#000000',
					shadowOffsetX: 0,
					shadowOffsetY: 0,
					shadowBlur: 0,
					shadowColor: 'rgba(0, 0, 0, 0)',
					lineWidth: 1,
					lineCap: 'butt',
					lineJoin: 'miter',
					miterLimit: 10,
					lineDashOffset: 0,
					font: '10px sans-serif',
					textAlign: 'start',
					textBaseline: 'alphabetic'
				};
			}
		}, {
			key: "initDataRange",
			value: function initDataRange(options) {
				var self = this;
				self.intensity = new Intensity({
					maxSize: self.options.maxSize,
					minSize: self.options.minSize,
					gradient: self.options.gradient,
					max: self.options.max || this.dataSet.getMax('count')
				});
				self.category = new Category(self.options.splitList);
				self.choropleth = new Choropleth(self.options.splitList);
				if (self.options.splitList === undefined) {
					self.category.generateByDataSet(this.dataSet, self.options.color);
				}
				if (self.options.splitList === undefined) {
					var min = self.options.min || this.dataSet.getMin('count');
					var max = self.options.max || this.dataSet.getMax('count');
					self.choropleth.generateByMinMax(min, max);
				}
			}
		}, {
			key: "getLegend",
			value: function getLegend(options) {
				var draw = this.options.draw;
				var legend = null;
				var self = this;
				if (self.options.draw == 'intensity' || self.options.draw == 'heatmap') {
					return this.intensity.getLegend(options);
				} else if (self.options.draw == 'category') {
					return this.category.getLegend(options);
				}
			}
		}, {
			key: "processData",
			value: function processData(data) {
				var self = this;
				var draw = self.options.draw;
				if (draw == 'bubble' || draw == 'intensity' || draw == 'category' || draw == 'choropleth' || draw ==
					'simple') {

					for (var i = 0; i < data.length; i++) {
						var item = data[i];

						if (self.options.draw == 'bubble') {
							data[i]._size = self.intensity.getSize(item.count);
						} else {
							data[i]._size = undefined;
						}

						var styleType = '_fillStyle';

						if (data[i].geometry.type === 'LineString' || self.options.styleType === 'stroke') {
							styleType = '_strokeStyle';
						}

						if (self.options.draw == 'intensity') {
							data[i][styleType] = self.intensity.getColor(item.count);
						} else if (self.options.draw == 'category') {
							data[i][styleType] = self.category.get(item.count);
						} else if (self.options.draw == 'choropleth') {
							data[i][styleType] = self.choropleth.get(item.count);
						}
					}
				}
			}
		}, {
			key: "isEnabledTime",
			value: function isEnabledTime() {

				var animationOptions = this.options.animation;

				var flag = animationOptions && !(animationOptions.enabled === false);

				return flag;
			}
		}, {
			key: "argCheck",
			value: function argCheck(options) {
				if (options.draw == 'heatmap') {
					if (options.strokeStyle) {
						console.warn(
							'[heatmap] options.strokeStyle is discard, pleause use options.strength [eg: options.strength = 0.1]');
					}
				}
			}
		}, {
			key: "drawContext",
			value: function drawContext(context, dataSet, options, nwPixel) {
				var self = this;
				switch (self.options.draw) {
					case 'heatmap':
						drawHeatmap.draw(context, dataSet, self.options);
						break;
					case 'grid':
					case 'cluster':
					case 'honeycomb':
						self.options.offset = {
							x: nwPixel.x,
							y: nwPixel.y
						};
						if (self.options.draw === 'grid') {
							drawGrid.draw(context, dataSet, self.options);
						} else if (self.options.draw === 'cluster') {
							drawCluster.draw(context, dataSet, self.options);
						} else {
							drawHoneycomb.draw(context, dataSet, self.options);
						}
						break;
					case 'text':
						drawText.draw(context, dataSet, self.options);
						break;
					case 'icon':
						drawIcon.draw(context, dataSet, self.options);
						break;
					case 'clip':
						drawClip.draw(context, dataSet, self.options);
						break;
					default:
						if (self.options.context == "webgl") {
							webglDrawSimple.draw(self.canvasLayer.canvas.getContext('webgl'), dataSet, self.options);
						} else {
							drawSimple.draw(context, dataSet, self.options);
						}
				}

				if (self.options.arrow && self.options.arrow.show !== false) {
					object.draw(context, dataSet, self.options);
				}
			}
		}, {
			key: "isPointInPath",
			value: function isPointInPath(context, pixel) {
				var context = this.canvasLayer.canvas.getContext(this.context);
				var data;
				if (this.options.draw === 'cluster') {
					data = this.clusterDataSet.get();
				} else {
					data = this.dataSet.get();
				}
				for (var i = 0; i < data.length; i++) {
					context.beginPath();
					var options = this.options;
					var x = pixel.x * this.canvasLayer.devicePixelRatio;
					var y = pixel.y * this.canvasLayer.devicePixelRatio;

					options.multiPolygonDraw = function() {
						if (context.isPointInPath(x, y)) {
							return data[i];
						}
					};

					pathSimple.draw(context, data[i], options);

					var geoType = data[i].geometry && data[i].geometry.type;
					if (geoType.indexOf('LineString') > -1) {
						if (context.isPointInStroke && context.isPointInStroke(x, y)) {
							return data[i];
						}
					} else {

						if (context.isPointInPath(x, y)) {
							return data[i];
						}
					}
				}
			}
		}, {
			key: "clickEvent",
			value: function clickEvent(pixel, e) {
				if (!this.options.methods) {
					return;
				}
				var dataItem = this.isPointInPath(this.getContext(), pixel);

				if (dataItem) {
					this.options.methods.click(dataItem, e);
				} else {
					this.options.methods.click(null, e);
				}
			}
		}, {
			key: "mousemoveEvent",
			value: function mousemoveEvent(pixel, e) {
				if (!this.options.methods) {
					return;
				}
				var dataItem = this.isPointInPath(this.getContext(), pixel);
				if (dataItem) {
					this.options.methods.mousemove(dataItem, e);
				} else {
					this.options.methods.mousemove(null, e);
				}
			}
		}, {
			key: "tapEvent",
			value: function tapEvent(pixel, e) {
				if (!this.options.methods) {
					return;
				}
				var dataItem = this.isPointInPath(this.getContext(), pixel);
				if (dataItem) {
					this.options.methods.tap(dataItem, e);
				} else {
					this.options.methods.tap(null, e);
				}
			}

			/**
			 * obj.options
			 */

		}, {
			key: "update",
			value: function update(obj, isDraw) {
				var self = this;
				var _options = obj.options;
				var options = self.options;
				for (var i in _options) {
					options[i] = _options[i];
				}
				self.init(options);
				if (isDraw !== false) {
					self.draw();
				}
			}
		}, {
			key: "setOptions",
			value: function setOptions(options) {
				var self = this;
				self.dataSet.reset();
				// console.log('xxx1')
				self.init(options);
				// console.log('xxx')
				self.draw();
			}
		}, {
			key: "set",
			value: function set$$1(obj) {
				var self = this;
				var ctx = this.getContext();
				var conf = this.getDefaultContextConfig();
				for (var i in conf) {
					ctx[i] = conf[i];
				}
				self.init(obj.options);
				self.draw();
			}
		}, {
			key: "destroy",
			value: function destroy() {
				this.unbindEvent();
				this.hide();
			}
		}, {
			key: "initAnimator",
			value: function initAnimator() {
				var self = this;
				var animationOptions = self.options.animation;

				if (self.options.draw == 'time' || self.isEnabledTime()) {

					if (!animationOptions.stepsRange) {
						animationOptions.stepsRange = {
							start: this.dataSet.getMin('time') || 0,
							end: this.dataSet.getMax('time') || 0
						};
					}

					this.steps = {
						step: animationOptions.stepsRange.start
					};
					self.animator = new TWEEN.Tween(this.steps).onUpdate(function() {
						self._canvasUpdate(this.step);
					}).repeat(Infinity);

					this.addAnimatorEvent();

					var duration = animationOptions.duration * 1000 || 5000;

					self.animator.to({
						step: animationOptions.stepsRange.end
					}, duration);
					self.animator.start();
				} else {
					self.animator && self.animator.stop();
				}
			}
		}, {
			key: "addAnimatorEvent",
			value: function addAnimatorEvent() {}
		}, {
			key: "animatorMovestartEvent",
			value: function animatorMovestartEvent() {
				var animationOptions = this.options.animation;
				if (this.isEnabledTime() && this.animator) {
					this.steps.step = animationOptions.stepsRange.start;
					this.animator.stop();
				}
			}
		}, {
			key: "animatorMoveendEvent",
			value: function animatorMoveendEvent() {
				if (this.isEnabledTime() && this.animator) {
					this.animator.start();
				}
			}
		}]);
		return BaseLayer;
	}();

	var AnimationLayer = function(_BaseLayer) {
		inherits(AnimationLayer, _BaseLayer);

		function AnimationLayer(map, dataSet, options) {
			classCallCheck(this, AnimationLayer);

			var _this = possibleConstructorReturn(this, (AnimationLayer.__proto__ || Object.getPrototypeOf(AnimationLayer)).call(
				this, map, dataSet, options));

			_this.map = map;
			_this.options = options || {};
			_this.dataSet = dataSet;

			var canvasLayer = new CanvasLayer({
				map: map,
				zIndex: _this.options.zIndex,
				update: _this._canvasUpdate.bind(_this)
			});

			_this.init(_this.options);

			_this.canvasLayer = canvasLayer;
			_this.transferToMercator();
			var self = _this;
			dataSet.on('change', function() {
				self.transferToMercator();
				canvasLayer.draw();
			});
			_this.ctx = canvasLayer.canvas.getContext('2d');

			_this.start();
			return _this;
		}

		createClass(AnimationLayer, [{
			key: "draw",
			value: function draw() {
				this.canvasLayer.draw();
			}
		}, {
			key: "init",
			value: function init(options) {

				var self = this;
				self.options = options;
				this.initDataRange(options);
				this.context = self.options.context || '2d';

				if (self.options.zIndex) {
					this.canvasLayer && this.canvasLayer.setZIndex(self.options.zIndex);
				}

				if (self.options.max) {
					this.intensity.setMax(self.options.max);
				}

				if (self.options.min) {
					this.intensity.setMin(self.options.min);
				}

				this.initAnimator();
			}

			// 经纬度左边转换为墨卡托坐标

		}, {
			key: "transferToMercator",
			value: function transferToMercator() {
				var projection = this.map.getMapType().getProjection();

				if (this.options.coordType !== 'bd09mc') {
					var data = this.dataSet.get();
					data = this.dataSet.transferCoordinate(data, function(coordinates) {
						var pixel = projection.lngLatToPoint({
							lng: coordinates[0],
							lat: coordinates[1]
						});
						return [pixel.x, pixel.y];
					}, 'coordinates', 'coordinates_mercator');
					this.dataSet._set(data);
				}
			}
		}, {
			key: "_canvasUpdate",
			value: function _canvasUpdate() {
				var ctx = this.ctx;
				if (!ctx) {
					return;
				}
				//clear(ctx);
				var map = this.map;
				var zoomUnit = Math.pow(2, 18 - map.getZoom());
				var projection = map.getMapType().getProjection();

				var mcCenter = projection.lngLatToPoint(map.getCenter());
				var nwMc = new BMap.Pixel(mcCenter.x - map.getSize().width / 2 * zoomUnit, mcCenter.y + map.getSize().height /
					2 * zoomUnit); //左上角墨卡托坐标

				clear(ctx);

				var dataGetOptions = {
					fromColumn: this.options.coordType == 'bd09mc' ? 'coordinates' : 'coordinates_mercator',
					transferCoordinate: function transferCoordinate(coordinate) {
						if (!coordinate) {
							return;
						}
						var x = (coordinate[0] - nwMc.x) / zoomUnit;
						var y = (nwMc.y - coordinate[1]) / zoomUnit;
						return [x, y];
					}
				};

				this.data = this.dataSet.get(dataGetOptions);

				this.processData(this.data);

				this.drawAnimation();
			}
		}, {
			key: "drawAnimation",
			value: function drawAnimation() {
				var ctx = this.ctx;
				var data = this.data;
				if (!data) {
					return;
				}

				ctx.save();
				ctx.globalCompositeOperation = 'destination-out';
				ctx.fillStyle = 'rgba(0, 0, 0, .1)';
				ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
				ctx.restore();

				ctx.save();
				if (this.options.shadowColor) {
					ctx.shadowColor = this.options.shadowColor;
				}

				if (this.options.shadowBlur) {
					ctx.shadowBlur = this.options.shadowBlur;
				}

				if (this.options.globalAlpha) {
					ctx.globalAlpha = this.options.globalAlpha;
				}

				if (this.options.globalCompositeOperation) {
					ctx.globalCompositeOperation = this.options.globalCompositeOperation;
				}

				var options = this.options;
				for (var i = 0; i < data.length; i++) {
					if (data[i].geometry.type === 'Point') {
						ctx.beginPath();
						var maxSize = data[i].size || this.options.size;
						var minSize = data[i].minSize || this.options.minSize || 0;
						if (data[i]._size === undefined) {
							data[i]._size = minSize;
						}
						ctx.arc(data[i].geometry._coordinates[0], data[i].geometry._coordinates[1], data[i]._size, 0, Math.PI * 2,
							true);
						ctx.closePath();

						data[i]._size++;

						if (data[i]._size > maxSize) {
							data[i]._size = minSize;
						}
						ctx.lineWidth = 1;
						ctx.strokeStyle = data[i].strokeStyle || data[i]._strokeStyle || options.strokeStyle || 'yellow';
						ctx.stroke();
						var fillStyle = data[i].fillStyle || data[i]._fillStyle || options.fillStyle;
						if (fillStyle) {
							ctx.fillStyle = fillStyle;
							ctx.fill();
						}
					} else if (data[i].geometry.type === 'LineString') {
						ctx.beginPath();
						var size = data[i].size || this.options.size || 5;
						var minSize = data[i].minSize || this.options.minSize || 0;
						if (data[i]._index === undefined) {
							data[i]._index = 0;
						}
						var index = data[i]._index;
						ctx.arc(data[i].geometry._coordinates[index][0], data[i].geometry._coordinates[index][1], size, 0, Math.PI *
							2, true);
						ctx.closePath();

						data[i]._index++;

						if (data[i]._index >= data[i].geometry._coordinates.length) {
							data[i]._index = 0;
						}

						var strokeStyle = data[i].strokeStyle || options.strokeStyle;
						var fillStyle = data[i].fillStyle || options.fillStyle || 'yellow';
						ctx.fillStyle = fillStyle;
						ctx.fill();
						if (strokeStyle && options.lineWidth) {
							ctx.lineWidth = options.lineWidth || 1;
							ctx.strokeStyle = strokeStyle;
							ctx.stroke();
						}
					}
				}
				ctx.restore();
			}
		}, {
			key: "animate",
			value: function animate() {
				this.drawAnimation();
				var animateTime = this.options.animateTime || 100;
				this.timeout = setTimeout(this.animate.bind(this), animateTime);
			}
		}, {
			key: "start",
			value: function start() {
				this.stop();
				this.animate();
			}
		}, {
			key: "stop",
			value: function stop() {
				clearTimeout(this.timeout);
			}
		}, {
			key: "unbindEvent",
			value: function unbindEvent() {}
		}, {
			key: "hide",
			value: function hide() {
				this.canvasLayer.hide();
				this.stop();
			}
		}, {
			key: "show",
			value: function show() {
				this.start();
			}
		}]);
		return AnimationLayer;
	}(BaseLayer);

	/**
	 * @author kyle / http://nikai.us/
	 */

	var Layer = function(_BaseLayer) {
		inherits(Layer, _BaseLayer);

		function Layer(map, dataSet, options) {
			classCallCheck(this, Layer);

			var _this = possibleConstructorReturn(this, (Layer.__proto__ || Object.getPrototypeOf(Layer)).call(this, map,
				dataSet, options));

			var self = _this;
			var data = null;
			options = options || {};

			_this.clickEvent = _this.clickEvent.bind(_this);
			_this.mousemoveEvent = _this.mousemoveEvent.bind(_this);
			_this.tapEvent = _this.tapEvent.bind(_this);

			self.init(options);
			self.argCheck(options);
			self.transferToMercator();

			var canvasLayer = _this.canvasLayer = new CanvasLayer({
				map: map,
				context: _this.context,
				paneName: options.paneName,
				mixBlendMode: options.mixBlendMode,
				enableMassClear: options.enableMassClear,
				zIndex: options.zIndex,
				update: function update() {
					self._canvasUpdate();
				}
			});

			dataSet.on('change', function() {
				self.transferToMercator();
				canvasLayer.draw();
			});

			return _this;
		}

		createClass(Layer, [{
			key: "clickEvent",
			value: function clickEvent(e) {
				var pixel = e.pixel;
				get(Layer.prototype.__proto__ || Object.getPrototypeOf(Layer.prototype), "clickEvent", this).call(this,
					pixel, e);
			}
		}, {
			key: "mousemoveEvent",
			value: function mousemoveEvent(e) {
				var pixel = e.pixel;
				get(Layer.prototype.__proto__ || Object.getPrototypeOf(Layer.prototype), "mousemoveEvent", this).call(this,
					pixel, e);
			}
		}, {
			key: "tapEvent",
			value: function tapEvent(e) {
				var pixel = e.pixel;
				get(Layer.prototype.__proto__ || Object.getPrototypeOf(Layer.prototype), "tapEvent", this).call(this, pixel,
					e);
			}
		}, {
			key: "bindEvent",
			value: function bindEvent(e) {
				this.unbindEvent();
				var map = this.map;
				var timer = 0;
				var that = this;

				if (this.options.methods) {
					if (this.options.methods.click) {
						map.setDefaultCursor("default");
						map.addEventListener('click', this.clickEvent);
					}
					if (this.options.methods.mousemove) {
						map.addEventListener('mousemove', this.mousemoveEvent);
					}

					if ("ontouchend" in window.document && this.options.methods.tap) {
						map.addEventListener('touchstart', function(e) {
							timer = new Date();
						});
						map.addEventListener('touchend', function(e) {
							if (new Date() - timer < 300) {
								that.tapEvent(e);
							}
						});
					}
				}
			}
		}, {
			key: "unbindEvent",
			value: function unbindEvent(e) {
				var map = this.map;

				if (this.options.methods) {
					if (this.options.methods.click) {
						map.removeEventListener('click', this.clickEvent);
					}
					if (this.options.methods.mousemove) {
						map.removeEventListener('mousemove', this.mousemoveEvent);
					}
				}
			}

			// 经纬度左边转换为墨卡托坐标

		}, {
			key: "transferToMercator",
			value: function transferToMercator(dataSet) {
				if (!dataSet) {
					dataSet = this.dataSet;
				}
				var projection = this.map.getMapType().getProjection();
				/* if(this.map.Get == undefined){
					var mapT = new BMap.Map("map",{minZoom:3,maxZoom:19,enableMapClick:false});
					projection = mapT.getMapType().getProjection();
				}
				else{
					projection = this.map.getMapType().getProjection();
				} */

				if (this.options.coordType !== 'bd09mc') {
					var data = dataSet.get();
					data = dataSet.transferCoordinate(data, function(coordinates) {
						if (coordinates[0] < -180 || coordinates[0] > 180 || coordinates[1] < -90 || coordinates[1] > 90) {
							return coordinates;
						} else {
							var pixel = projection.lngLatToPoint({
								lng: coordinates[0],
								lat: coordinates[1]
							});
							return [pixel.x, pixel.y];
						}
					}, 'coordinates', 'coordinates_mercator');
					dataSet._set(data);
				}
			}
		}, {
			key: "getContext",
			value: function getContext() {
				return this.canvasLayer.canvas.getContext(this.context);
			}
		}, {
			key: "_canvasUpdate",
			value: function _canvasUpdate(time) {
				if (!this.canvasLayer) {
					return;
				}

				var self = this;

				var animationOptions = self.options.animation;

				var map = this.canvasLayer._map;

				var zoomUnit = Math.pow(2, 18 - map.getZoom());
				var projection = map.getMapType().getProjection();

				var mcCenter = projection.lngLatToPoint(map.getCenter());
				var nwMc = new BMap.Pixel(mcCenter.x - map.getSize().width / 2 * zoomUnit, mcCenter.y + map.getSize().height /
					2 * zoomUnit); //左上角墨卡托坐标

				var context = this.getContext();

				if (self.isEnabledTime()) {
					if (time === undefined) {
						clear(context);
						return;
					}
					if (this.context == '2d') {
						context.save();
						context.globalCompositeOperation = 'destination-out';
						context.fillStyle = 'rgba(0, 0, 0, .1)';
						context.fillRect(0, 0, context.canvas.width, context.canvas.height);
						context.restore();
					}
				} else {
					clear(context);
				}

				if (this.context == '2d') {
					for (var key in self.options) {
						context[key] = self.options[key];
					}
				} else {
					context.clear(context.COLOR_BUFFER_BIT);
				}

				if (self.options.minZoom && map.getZoom() < self.options.minZoom || self.options.maxZoom && map.getZoom() >
					self.options.maxZoom) {
					return;
				}

				var scale = 1;
				if (this.context != '2d') {
					scale = this.canvasLayer.devicePixelRatio;
				}

				var dataGetOptions = {
					fromColumn: self.options.coordType == 'bd09mc' ? 'coordinates' : 'coordinates_mercator',
					transferCoordinate: function transferCoordinate(coordinate) {
						var x = (coordinate[0] - nwMc.x) / zoomUnit * scale;
						var y = (nwMc.y - coordinate[1]) / zoomUnit * scale;
						return [x, y];
					}
				};

				if (time !== undefined) {
					dataGetOptions.filter = function(item) {
						var trails = animationOptions.trails || 10;
						if (time && item.time > time - trails && item.time < time) {
							return true;
						} else {
							return false;
						}
					};
				}

				// get data from data set
				var data;

				if (self.options.draw === 'cluster') {
					var bounds = this.map.getBounds();
					var ne = bounds.getNorthEast();
					var sw = bounds.getSouthWest();
					var clusterData = this.supercluster.getClusters([sw.lng, sw.lat, ne.lng, ne.lat], this.getZoom());
					this.clusterDataSet.set(clusterData);
					this.transferToMercator(this.clusterDataSet);
					data = this.clusterDataSet.get(dataGetOptions);
				} else {
					data = self.dataSet.get(dataGetOptions);
				}

				this.processData(data);

				var nwPixel = map.pointToPixel(new BMap.Point(0, 0));

				if (self.options.unit == 'm') {
					if (self.options.size) {
						self.options._size = self.options.size / zoomUnit;
					}
					if (self.options.width) {
						self.options._width = self.options.width / zoomUnit;
					}
					if (self.options.height) {
						self.options._height = self.options.height / zoomUnit;
					}
				} else {
					self.options._size = self.options.size;
					self.options._height = self.options.height;
					self.options._width = self.options.width;
				}

				this.drawContext(context, data, self.options, nwPixel);

				//console.timeEnd('draw');

				//console.timeEnd('update')
				self.options.updateCallback && self.options.updateCallback(time);
			}
		}, {
			key: "init",
			value: function init(options) {

				var self = this;
				self.options = options;
				this.initDataRange(options);
				this.context = self.options.context || '2d';

				if (self.options.zIndex) {
					this.canvasLayer && this.canvasLayer.setZIndex(self.options.zIndex);
				}

				if (self.options.max) {
					this.intensity.setMax(self.options.max);
				}

				if (self.options.min) {
					this.intensity.setMin(self.options.min);
				}

				this.initAnimator();
				this.bindEvent();
			}
		}, {
			key: "getZoom",
			value: function getZoom() {
				return this.map.getZoom();
			}
		}, {
			key: "addAnimatorEvent",
			value: function addAnimatorEvent() {
				this.map.addEventListener('movestart', this.animatorMovestartEvent.bind(this));
				this.map.addEventListener('moveend', this.animatorMoveendEvent.bind(this));
			}
		}, {
			key: "show",
			value: function show() {
				this.map.addOverlay(this.canvasLayer);
			}
		}, {
			key: "hide",
			value: function hide() {
				this.map.removeOverlay(this.canvasLayer);
			}
		}, {
			key: "draw",
			value: function draw() {
				this.canvasLayer.draw();
			}
		}]);
		return Layer;
	}(BaseLayer);

	/**
	 * Copyright 2012 Google Inc. All Rights Reserved.
	 *
	 * Licensed under the Apache License, Version 2.0 (the "License");
	 * you may not use this file except in compliance with the License.
	 * You may obtain a copy of the License at
	 *
	 *     http://www.apache.org/licenses/LICENSE-2.0
	 *
	 * Unless required by applicable law or agreed to in writing, software
	 * distributed under the License is distributed on an "AS IS" BASIS,
	 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	 * See the License for the specific language governing permissions and
	 * limitations under the License.
	 */

	/**
	 * @fileoverview Extends OverlayView to provide a canvas "Layer".
	 * @author Brendan Kenny
	 */

	/**
	 * A map layer that provides a canvas over the slippy map and a callback
	 * system for efficient animation. Requires canvas and CSS 2D transform
	 * support.
	 * @constructor
	 * @extends google.maps.OverlayView
	 * @param {CanvasLayerOptions=} opt_options Options to set in this CanvasLayer.
	 */
	function CanvasLayer$2(opt_options) {
		/**
		 * If true, canvas is in a map pane and the OverlayView is fully functional.
		 * See google.maps.OverlayView.onAdd for more information.
		 * @type {boolean}
		 * @private
		 */
		this.isAdded_ = false;

		/**
		 * If true, each update will immediately schedule the next.
		 * @type {boolean}
		 * @private
		 */
		this.isAnimated_ = false;

		/**
		 * The name of the MapPane in which this layer will be displayed.
		 * @type {string}
		 * @private
		 */
		this.paneName_ = CanvasLayer$2.DEFAULT_PANE_NAME_;

		/**
		 * A user-supplied function called whenever an update is required. Null or
		 * undefined if a callback is not provided.
		 * @type {?function=}
		 * @private
		 */
		this.updateHandler_ = null;

		/**
		 * A user-supplied function called whenever an update is required and the
		 * map has been resized since the last update. Null or undefined if a
		 * callback is not provided.
		 * @type {?function}
		 * @private
		 */
		this.resizeHandler_ = null;

		/**
		 * The LatLng coordinate of the top left of the current view of the map. Will
		 * be null when this.isAdded_ is false.
		 * @type {google.maps.LatLng}
		 * @private
		 */
		this.topLeft_ = null;

		/**
		 * The map-pan event listener. Will be null when this.isAdded_ is false. Will
		 * be null when this.isAdded_ is false.
		 * @type {?function}
		 * @private
		 */
		this.centerListener_ = null;

		/**
		 * The map-resize event listener. Will be null when this.isAdded_ is false.
		 * @type {?function}
		 * @private
		 */
		this.resizeListener_ = null;

		/**
		 * If true, the map size has changed and this.resizeHandler_ must be called
		 * on the next update.
		 * @type {boolean}
		 * @private
		 */
		this.needsResize_ = true;

		/**
		 * A browser-defined id for the currently requested callback. Null when no
		 * callback is queued.
		 * @type {?number}
		 * @private
		 */
		this.requestAnimationFrameId_ = null;

		var canvas = document.createElement('canvas');
		canvas.style.position = 'absolute';
		canvas.style.top = 0;
		canvas.style.left = 0;
		canvas.style.pointerEvents = 'none';

		/**
		 * The canvas element.
		 * @type {!HTMLCanvasElement}
		 */
		this.canvas = canvas;

		/**
		 * The CSS width of the canvas, which may be different than the width of the
		 * backing store.
		 * @private {number}
		 */
		this.canvasCssWidth_ = 300;

		/**
		 * The CSS height of the canvas, which may be different than the height of
		 * the backing store.
		 * @private {number}
		 */
		this.canvasCssHeight_ = 150;

		/**
		 * A value for scaling the CanvasLayer resolution relative to the CanvasLayer
		 * display size.
		 * @private {number}
		 */
		this.resolutionScale_ = 1;

		/**
		 * Simple bind for functions with no args for bind-less browsers (Safari).
		 * @param {Object} thisArg The this value used for the target function.
		 * @param {function} func The function to be bound.
		 */
		function simpleBindShim(thisArg, func) {
			return function() {
				func.apply(thisArg);
			};
		}

		/**
		 * A reference to this.repositionCanvas_ with this bound as its this value.
		 * @type {function}
		 * @private
		 */
		this.repositionFunction_ = simpleBindShim(this, this.repositionCanvas_);

		/**
		 * A reference to this.resize_ with this bound as its this value.
		 * @type {function}
		 * @private
		 */
		this.resizeFunction_ = simpleBindShim(this, this.resize_);

		/**
		 * A reference to this.update_ with this bound as its this value.
		 * @type {function}
		 * @private
		 */
		this.requestUpdateFunction_ = simpleBindShim(this, this.update_);

		// set provided options, if any
		if (opt_options) {
			this.setOptions(opt_options);
		}
	}

	var global$4 = typeof window === 'undefined' ? {} : window;

	if (global$4.google && global$4.google.maps) {

		CanvasLayer$2.prototype = new google.maps.OverlayView();

		/**
		 * The default MapPane to contain the canvas.
		 * @type {string}
		 * @const
		 * @private
		 */
		CanvasLayer$2.DEFAULT_PANE_NAME_ = 'overlayLayer';

		/**
		 * Transform CSS property name, with vendor prefix if required. If browser
		 * does not support transforms, property will be ignored.
		 * @type {string}
		 * @const
		 * @private
		 */
		CanvasLayer$2.CSS_TRANSFORM_ = function() {
			var div = document.createElement('div');
			var transformProps = ['transform', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform'];
			for (var i = 0; i < transformProps.length; i++) {
				var prop = transformProps[i];
				if (div.style[prop] !== undefined) {
					return prop;
				}
			}

			// return unprefixed version by default
			return transformProps[0];
		}();

		/**
		 * The requestAnimationFrame function, with vendor-prefixed or setTimeout-based
		 * fallbacks. MUST be called with window as thisArg.
		 * @type {function}
		 * @param {function} callback The function to add to the frame request queue.
		 * @return {number} The browser-defined id for the requested callback.
		 * @private
		 */
		CanvasLayer$2.prototype.requestAnimFrame_ = global$4.requestAnimationFrame || global$4.webkitRequestAnimationFrame ||
			global$4.mozRequestAnimationFrame || global$4.oRequestAnimationFrame || global$4.msRequestAnimationFrame ||
			function(callback) {
				return global$4.setTimeout(callback, 1000 / 60);
			};

		/**
		 * The cancelAnimationFrame function, with vendor-prefixed fallback. Does not
		 * fall back to clearTimeout as some platforms implement requestAnimationFrame
		 * but not cancelAnimationFrame, and the cost is an extra frame on onRemove.
		 * MUST be called with window as thisArg.
		 * @type {function}
		 * @param {number=} requestId The id of the frame request to cancel.
		 * @private
		 */
		CanvasLayer$2.prototype.cancelAnimFrame_ = global$4.cancelAnimationFrame || global$4.webkitCancelAnimationFrame ||
			global$4.mozCancelAnimationFrame || global$4.oCancelAnimationFrame || global$4.msCancelAnimationFrame || function(
				requestId) {};

		/**
		 * Sets any options provided. See CanvasLayerOptions for more information.
		 * @param {CanvasLayerOptions} options The options to set.
		 */
		CanvasLayer$2.prototype.setOptions = function(options) {
			if (options.animate !== undefined) {
				this.setAnimate(options.animate);
			}

			if (options.paneName !== undefined) {
				this.setPaneName(options.paneName);
			}

			if (options.updateHandler !== undefined) {
				this.setUpdateHandler(options.updateHandler);
			}

			if (options.resizeHandler !== undefined) {
				this.setResizeHandler(options.resizeHandler);
			}

			if (options.resolutionScale !== undefined) {
				this.setResolutionScale(options.resolutionScale);
			}

			if (options.map !== undefined) {
				this.setMap(options.map);
			}
		};

		/**
		 * Set the animated state of the layer. If true, updateHandler will be called
		 * repeatedly, once per frame. If false, updateHandler will only be called when
		 * a map property changes that could require the canvas content to be redrawn.
		 * @param {boolean} animate Whether the canvas is animated.
		 */
		CanvasLayer$2.prototype.setAnimate = function(animate) {
			this.isAnimated_ = !!animate;

			if (this.isAnimated_) {
				this.scheduleUpdate();
			}
		};

		/**
		 * @return {boolean} Whether the canvas is animated.
		 */
		CanvasLayer$2.prototype.isAnimated = function() {
			return this.isAnimated_;
		};

		/**
		 * Set the MapPane in which this layer will be displayed, by name. See
		 * {@code google.maps.MapPanes} for the panes available.
		 * @param {string} paneName The name of the desired MapPane.
		 */
		CanvasLayer$2.prototype.setPaneName = function(paneName) {
			this.paneName_ = paneName;

			this.setPane_();
		};

		/**
		 * @return {string} The name of the current container pane.
		 */
		CanvasLayer$2.prototype.getPaneName = function() {
			return this.paneName_;
		};

		/**
		 * Adds the canvas to the specified container pane. Since this is guaranteed to
		 * execute only after onAdd is called, this is when paneName's existence is
		 * checked (and an error is thrown if it doesn't exist).
		 * @private
		 */
		CanvasLayer$2.prototype.setPane_ = function() {
			if (!this.isAdded_) {
				return;
			}

			// onAdd has been called, so panes can be used
			var panes = this.getPanes();
			if (!panes[this.paneName_]) {
				throw new Error('"' + this.paneName_ + '" is not a valid MapPane name.');
			}

			panes[this.paneName_].appendChild(this.canvas);
		};

		/**
		 * Set a function that will be called whenever the parent map and the overlay's
		 * canvas have been resized. If opt_resizeHandler is null or unspecified, any
		 * existing callback is removed.
		 * @param {?function=} opt_resizeHandler The resize callback function.
		 */
		CanvasLayer$2.prototype.setResizeHandler = function(opt_resizeHandler) {
			this.resizeHandler_ = opt_resizeHandler;
		};

		/**
		 * Sets a value for scaling the canvas resolution relative to the canvas
		 * display size. This can be used to save computation by scaling the backing
		 * buffer down, or to support high DPI devices by scaling it up (by e.g.
		 * window.devicePixelRatio).
		 * @param {number} scale
		 */
		CanvasLayer$2.prototype.setResolutionScale = function(scale) {
			if (typeof scale === 'number') {
				this.resolutionScale_ = scale;
				this.resize_();
			}
		};

		/**
		 * Set a function that will be called when a repaint of the canvas is required.
		 * If opt_updateHandler is null or unspecified, any existing callback is
		 * removed.
		 * @param {?function=} opt_updateHandler The update callback function.
		 */
		CanvasLayer$2.prototype.setUpdateHandler = function(opt_updateHandler) {
			this.updateHandler_ = opt_updateHandler;
		};

		/**
		 * @inheritDoc
		 */
		CanvasLayer$2.prototype.onAdd = function() {
			if (this.isAdded_) {
				return;
			}

			this.isAdded_ = true;
			this.setPane_();

			this.resizeListener_ = google.maps.event.addListener(this.getMap(), 'resize', this.resizeFunction_);
			this.centerListener_ = google.maps.event.addListener(this.getMap(), 'center_changed', this.repositionFunction_);

			this.resize_();
			this.repositionCanvas_();
		};

		/**
		 * @inheritDoc
		 */
		CanvasLayer$2.prototype.onRemove = function() {
			if (!this.isAdded_) {
				return;
			}

			this.isAdded_ = false;
			this.topLeft_ = null;

			// remove canvas and listeners for pan and resize from map
			this.canvas.parentElement.removeChild(this.canvas);
			if (this.centerListener_) {
				google.maps.event.removeListener(this.centerListener_);
				this.centerListener_ = null;
			}
			if (this.resizeListener_) {
				google.maps.event.removeListener(this.resizeListener_);
				this.resizeListener_ = null;
			}

			// cease canvas update callbacks
			if (this.requestAnimationFrameId_) {
				this.cancelAnimFrame_.call(global$4, this.requestAnimationFrameId_);
				this.requestAnimationFrameId_ = null;
			}
		};

		/**
		 * The internal callback for resize events that resizes the canvas to keep the
		 * map properly covered.
		 * @private
		 */
		CanvasLayer$2.prototype.resize_ = function() {
			if (!this.isAdded_) {
				return;
			}

			var map = this.getMap();
			var mapWidth = map.getDiv().offsetWidth;
			var mapHeight = map.getDiv().offsetHeight;

			var newWidth = mapWidth * this.resolutionScale_;
			var newHeight = mapHeight * this.resolutionScale_;
			var oldWidth = this.canvas.width;
			var oldHeight = this.canvas.height;

			// resizing may allocate a new back buffer, so do so conservatively
			if (oldWidth !== newWidth || oldHeight !== newHeight) {
				this.canvas.width = newWidth;
				this.canvas.height = newHeight;

				this.needsResize_ = true;
				this.scheduleUpdate();
			}

			// reset styling if new sizes don't match; resize of data not needed
			if (this.canvasCssWidth_ !== mapWidth || this.canvasCssHeight_ !== mapHeight) {
				this.canvasCssWidth_ = mapWidth;
				this.canvasCssHeight_ = mapHeight;
				this.canvas.style.width = mapWidth + 'px';
				this.canvas.style.height = mapHeight + 'px';
			}
		};

		/**
		 * @inheritDoc
		 */
		CanvasLayer$2.prototype.draw = function() {
			this.repositionCanvas_();
		};

		/**
		 * Internal callback for map view changes. Since the Maps API moves the overlay
		 * along with the map, this function calculates the opposite translation to
		 * keep the canvas in place.
		 * @private
		 */
		CanvasLayer$2.prototype.repositionCanvas_ = function() {
			// TODO(bckenny): *should* only be executed on RAF, but in current browsers
			//     this causes noticeable hitches in map and overlay relative
			//     positioning.

			var map = this.getMap();

			// topLeft can't be calculated from map.getBounds(), because bounds are
			// clamped to -180 and 180 when completely zoomed out. Instead, calculate
			// left as an offset from the center, which is an unwrapped LatLng.
			var top = map.getBounds().getNorthEast().lat();
			var center = map.getCenter();
			var scale = Math.pow(2, map.getZoom());
			var left = center.lng() - this.canvasCssWidth_ * 180 / (256 * scale);
			this.topLeft_ = new google.maps.LatLng(top, left);

			// Canvas position relative to draggable map's container depends on
			// overlayView's projection, not the map's. Have to use the center of the
			// map for this, not the top left, for the same reason as above.
			var projection = this.getProjection();
			var divCenter = projection.fromLatLngToDivPixel(center);
			var offsetX = -Math.round(this.canvasCssWidth_ / 2 - divCenter.x);
			var offsetY = -Math.round(this.canvasCssHeight_ / 2 - divCenter.y);
			this.canvas.style[CanvasLayer$2.CSS_TRANSFORM_] = 'translate(' + offsetX + 'px,' + offsetY + 'px)';

			this.scheduleUpdate();
		};

		/**
		 * Internal callback that serves as main animation scheduler via
		 * requestAnimationFrame. Calls resize and update callbacks if set, and
		 * schedules the next frame if overlay is animated.
		 * @private
		 */
		CanvasLayer$2.prototype.update_ = function() {
			this.requestAnimationFrameId_ = null;

			if (!this.isAdded_) {
				return;
			}

			if (this.isAnimated_) {
				this.scheduleUpdate();
			}

			if (this.needsResize_ && this.resizeHandler_) {
				this.needsResize_ = false;
				this.resizeHandler_();
			}

			if (this.updateHandler_) {
				this.updateHandler_();
			}
		};

		/**
		 * A convenience method to get the current LatLng coordinate of the top left of
		 * the current view of the map.
		 * @return {google.maps.LatLng} The top left coordinate.
		 */
		CanvasLayer$2.prototype.getTopLeft = function() {
			return this.topLeft_;
		};

		/**
		 * Schedule a requestAnimationFrame callback to updateHandler. If one is
		 * already scheduled, there is no effect.
		 */
		CanvasLayer$2.prototype.scheduleUpdate = function() {
			if (this.isAdded_ && !this.requestAnimationFrameId_) {
				this.requestAnimationFrameId_ = this.requestAnimFrame_.call(global$4, this.requestUpdateFunction_);
			}
		};
	}

	/**
	 * @author kyle / http://nikai.us/
	 */

	var Layer$2 = function(_BaseLayer) {
		inherits(Layer, _BaseLayer);

		function Layer(map, dataSet, options) {
			classCallCheck(this, Layer);

			var _this = possibleConstructorReturn(this, (Layer.__proto__ || Object.getPrototypeOf(Layer)).call(this, map,
				dataSet, options));

			var self = _this;
			var data = null;
			options = options || {};

			self.init(options);
			self.argCheck(options);

			var canvasLayerOptions = {
				map: map,
				animate: false,
				updateHandler: function updateHandler() {
					self._canvasUpdate();
				},
				resolutionScale: resolutionScale
			};

			var canvasLayer = _this.canvasLayer = new CanvasLayer$2(canvasLayerOptions);

			_this.clickEvent = _this.clickEvent.bind(_this);
			_this.mousemoveEvent = _this.mousemoveEvent.bind(_this);
			_this.bindEvent();
			return _this;
		}

		createClass(Layer, [{
			key: "clickEvent",
			value: function clickEvent(e) {
				var pixel = e.pixel;
				get(Layer.prototype.__proto__ || Object.getPrototypeOf(Layer.prototype), "clickEvent", this).call(this,
					pixel, e);
			}
		}, {
			key: "mousemoveEvent",
			value: function mousemoveEvent(e) {
				var pixel = e.pixel;
				get(Layer.prototype.__proto__ || Object.getPrototypeOf(Layer.prototype), "mousemoveEvent", this).call(this,
					pixel, e);
			}
		}, {
			key: "bindEvent",
			value: function bindEvent(e) {
				var map = this.map;

				if (this.options.methods) {
					if (this.options.methods.click) {
						map.setDefaultCursor("default");
						map.addListener('click', this.clickEvent);
					}
					if (this.options.methods.mousemove) {
						map.addListener('mousemove', this.mousemoveEvent);
					}
				}
			}
		}, {
			key: "unbindEvent",
			value: function unbindEvent(e) {
				var map = this.map;

				if (this.options.methods) {
					if (this.options.methods.click) {
						map.removeListener('click', this.clickEvent);
					}
					if (this.options.methods.mousemove) {
						map.removeListener('mousemove', this.mousemoveEvent);
					}
				}
			}
		}, {
			key: "getContext",
			value: function getContext() {
				return this.canvasLayer.canvas.getContext(this.context);
			}
		}, {
			key: "_canvasUpdate",
			value: function _canvasUpdate(time) {
				if (!this.canvasLayer) {
					return;
				}

				var self = this;

				var animationOptions = self.options.animation;

				var context = this.getContext();

				if (self.isEnabledTime()) {
					if (time === undefined) {
						clear(context);
						return;
					}
					if (this.context == '2d') {
						context.save();
						context.globalCompositeOperation = 'destination-out';
						context.fillStyle = 'rgba(0, 0, 0, .1)';
						context.fillRect(0, 0, context.canvas.width, context.canvas.height);
						context.restore();
					}
				} else {
					clear(context);
				}

				if (this.context == '2d') {
					for (var key in self.options) {
						context[key] = self.options[key];
					}
				} else {
					context.clear(context.COLOR_BUFFER_BIT);
				}

				if (self.options.minZoom && map.getZoom() < self.options.minZoom || self.options.maxZoom && map.getZoom() >
					self.options.maxZoom) {
					return;
				}

				var scale = 1;
				if (this.context != '2d') {
					scale = this.canvasLayer.devicePixelRatio;
				}

				var map = this.map;
				var mapProjection = map.getProjection();
				var scale = Math.pow(2, map.zoom) * resolutionScale;
				var offset = mapProjection.fromLatLngToPoint(this.canvasLayer.getTopLeft());
				var dataGetOptions = {
					//fromColumn: self.options.coordType == 'bd09mc' ? 'coordinates' : 'coordinates_mercator',
					transferCoordinate: function transferCoordinate(coordinate) {
						var latLng = new google.maps.LatLng(coordinate[1], coordinate[0]);
						var worldPoint = mapProjection.fromLatLngToPoint(latLng);
						var pixel = {
							x: (worldPoint.x - offset.x) * scale,
							y: (worldPoint.y - offset.y) * scale
						};
						return [pixel.x, pixel.y];
					}
				};

				if (time !== undefined) {
					dataGetOptions.filter = function(item) {
						var trails = animationOptions.trails || 10;
						if (time && item.time > time - trails && item.time < time) {
							return true;
						} else {
							return false;
						}
					};
				}

				// get data from data set
				var data = self.dataSet.get(dataGetOptions);

				this.processData(data);

				var latLng = new google.maps.LatLng(0, 0);
				var worldPoint = mapProjection.fromLatLngToPoint(latLng);
				var pixel = {
					x: (worldPoint.x - offset.x) * scale,
					y: (worldPoint.y - offset.y) * scale
				};

				if (self.options.unit == 'm' && self.options.size) {
					self.options._size = self.options.size / zoomUnit;
				} else {
					self.options._size = self.options.size;
				}

				this.drawContext(context, new DataSet(data), self.options, pixel);

				//console.timeEnd('draw');

				//console.timeEnd('update')
				self.options.updateCallback && self.options.updateCallback(time);
			}
		}, {
			key: "init",
			value: function init(options) {

				var self = this;

				self.options = options;

				this.initDataRange(options);

				this.context = self.options.context || '2d';

				if (self.options.zIndex) {
					this.canvasLayer && this.canvasLayer.setZIndex(self.options.zIndex);
				}

				this.initAnimator();
			}
		}, {
			key: "addAnimatorEvent",
			value: function addAnimatorEvent() {
				this.map.addListener('movestart', this.animatorMovestartEvent.bind(this));
				this.map.addListener('moveend', this.animatorMoveendEvent.bind(this));
			}
		}, {
			key: "show",
			value: function show() {
				this.map.addOverlay(this.canvasLayer);
			}
		}, {
			key: "hide",
			value: function hide() {
				this.map.removeOverlay(this.canvasLayer);
			}
		}, {
			key: "draw",
			value: function draw() {
				self.canvasLayer.draw();
			}
		}]);
		return Layer;
	}(BaseLayer);

	/**
	 * MapV for maptalks.js (https://github.com/maptalks/maptalks.js)
	 * @author fuzhenn / https://github.com/fuzhenn
	 */
	// import * as maptalks from 'maptalks';
	var Layer$4 = void 0;
	if (typeof maptalks !== 'undefined') {
		Layer$4 = function(_maptalks$Layer) {
			inherits(Layer, _maptalks$Layer);

			function Layer(id, dataSet, options) {
				classCallCheck(this, Layer);

				var _this = possibleConstructorReturn(this, (Layer.__proto__ || Object.getPrototypeOf(Layer)).call(this, id,
					options));

				_this.options_ = options;
				_this.dataSet = dataSet;
				_this._initBaseLayer(options);
				return _this;
			}

			createClass(Layer, [{
				key: "_initBaseLayer",
				value: function _initBaseLayer(options) {
					var self = this;
					var baseLayer = this.baseLayer = new BaseLayer(null, this.dataSet, options);
					self.init(options);
					baseLayer.argCheck(options);
				}
			}, {
				key: "clickEvent",
				value: function clickEvent(e) {
					if (!this.baseLayer) {
						return;
					}
					var pixel = e.containerPoint;
					this.baseLayer.clickEvent(pixel, e.domEvent);
				}
			}, {
				key: "mousemoveEvent",
				value: function mousemoveEvent(e) {
					if (!this.baseLayer) {
						return;
					}
					var pixel = e.containerPoint;
					this.baseLayer.mousemoveEvent(pixel, e.domEvent);
				}
			}, {
				key: "getEvents",
				value: function getEvents() {
					return {
						'click': this.clickEvent,
						'mousemove': this.mousemoveEvent
					};
				}
			}, {
				key: "init",
				value: function init(options) {

					var base = this.baseLayer;

					base.options = options;

					base.initDataRange(options);

					base.context = base.options.context || '2d';

					base.initAnimator();
				}
			}, {
				key: "addAnimatorEvent",
				value: function addAnimatorEvent() {
					this.map.addListener('movestart', this.animatorMovestartEvent.bind(this));
					this.map.addListener('moveend', this.animatorMoveendEvent.bind(this));
				}
			}]);
			return Layer;
		}(maptalks.Layer);

		var LayerRenderer = function(_maptalks$renderer$Ca) {
			inherits(LayerRenderer, _maptalks$renderer$Ca);

			function LayerRenderer() {
				classCallCheck(this, LayerRenderer);
				return possibleConstructorReturn(this, (LayerRenderer.__proto__ || Object.getPrototypeOf(LayerRenderer)).apply(
					this, arguments));
			}

			createClass(LayerRenderer, [{
				key: "needToRedraw",
				value: function needToRedraw() {
					var base = this.layer.baseLayer;
					if (base.isEnabledTime()) {
						return true;
					}
					return get(LayerRenderer.prototype.__proto__ || Object.getPrototypeOf(LayerRenderer.prototype),
						"needToRedraw", this).call(this);
				}
			}, {
				key: "draw",
				value: function draw() {
					var base = this.layer.baseLayer;
					if (!this.canvas || !base.isEnabledTime() || this._shouldClear) {
						this.prepareCanvas();
						this._shouldClear = false;
					}
					this._update(this.gl || this.context, this._mapvFrameTime);
					delete this._mapvFrameTime;
					this.completeRender();
				}
			}, {
				key: "drawOnInteracting",
				value: function drawOnInteracting() {
					this.draw();
					this._shouldClear = false;
				}
			}, {
				key: "onSkipDrawOnInteracting",
				value: function onSkipDrawOnInteracting() {
					this._shouldClear = true;
				}
			}, {
				key: "_canvasUpdate",
				value: function _canvasUpdate(time) {
					this.setToRedraw();
					this._mapvFrameTime = time;
				}
			}, {
				key: "_update",
				value: function _update(context, time) {
					if (!this.canvas) {
						return;
					}

					var self = this.layer.baseLayer;

					var animationOptions = self.options.animation;

					var map = this.getMap();

					if (self.isEnabledTime()) {
						if (time === undefined) {
							clear(context);
							return;
						}
						if (self.context == '2d') {
							context.save();
							context.globalCompositeOperation = 'destination-out';
							context.fillStyle = 'rgba(0, 0, 0, .1)';
							context.fillRect(0, 0, context.canvas.width, context.canvas.height);
							context.restore();
						}
					} else {
						clear(context);
					}

					if (self.context == '2d') {
						for (var key in self.options) {
							context[key] = self.options[key];
						}
					} else {
						context.clear(context.COLOR_BUFFER_BIT);
					}

					var scale = 1;
					if (self.context === '2d' && self.options.draw !== 'heatmap') {
						//in heatmap.js, devicePixelRatio is being mulitplied independently
						scale = self.canvasLayer.devicePixelRatio;
					}

					//reuse to save coordinate instance creation
					var coord = new maptalks.Coordinate(0, 0);
					var dataGetOptions = {
						fromColumn: self.options.coordType === 'bd09mc' ? 'coordinates_mercator' : 'coordinates',
						transferCoordinate: function transferCoordinate(coordinate) {
							coord.x = coordinate[0];
							coord.y = coordinate[1];
							var r = map.coordToContainerPoint(coord)._multi(scale).toArray();
							return r;
						}
					};

					if (time !== undefined) {
						dataGetOptions.filter = function(item) {
							var trails = animationOptions.trails || 10;
							if (time && item.time > time - trails && item.time < time) {
								return true;
							} else {
								return false;
							}
						};
					}

					// get data from data set
					var data = self.dataSet.get(dataGetOptions);

					self.processData(data);

					if (self.options.unit == 'm') {
						if (self.options.size) {
							self.options._size = self.options.size / zoomUnit;
						}
						if (self.options.width) {
							self.options._width = self.options.width / zoomUnit;
						}
						if (self.options.height) {
							self.options._height = self.options.height / zoomUnit;
						}
					} else {
						self.options._size = self.options.size;
						self.options._height = self.options.height;
						self.options._width = self.options.width;
					}

					var zeroZero = new maptalks.Point(0, 0);
					//screen position of the [0, 0] point
					var zeroZeroScreen = map._pointToContainerPoint(zeroZero)._multi(scale);
					self.drawContext(context, data, self.options, zeroZeroScreen);

					//console.timeEnd('draw');

					//console.timeEnd('update')
					self.options.updateCallback && self.options.updateCallback(time);
				}
			}, {
				key: "createCanvas",
				value: function createCanvas() {
					if (this.canvas) {
						return;
					}
					var map = this.getMap();
					var size = map.getSize();
					var r = maptalks.Browser.retina ? 2 : 1,
						w = r * size.width,
						h = r * size.height;
					this.canvas = maptalks.Canvas.createCanvas(w, h, map.CanvasClass);
					var mapvContext = this.layer.baseLayer.context;
					if (mapvContext === '2d') {
						this.context = this.canvas.getContext('2d');
						if (this.layer.options['globalCompositeOperation']) {
							this.context.globalCompositeOperation = this.layer.options['globalCompositeOperation'];
						}
					} else {
						var attributes = {
							'alpha': true,
							'preserveDrawingBuffer': true,
							'antialias': false
						};
						this.gl = this.canvas.getContext('webgl', attributes);
					}

					this.onCanvasCreate();

					this._bindToMapv();

					this.layer.fire('canvascreate', {
						'context': this.context,
						'gl': this.gl
					});
				}
			}, {
				key: "_bindToMapv",
				value: function _bindToMapv() {
					//some bindings needed by mapv baselayer
					var base = this.layer.baseLayer;
					this.devicePixelRatio = maptalks.Browser.retina ? 2 : 1;
					base.canvasLayer = this;
					base._canvasUpdate = this._canvasUpdate.bind(this);
					base.getContext = function() {
						var renderer = self.getRenderer();
						return renderer.gl || renderer.context;
					};
				}
			}]);
			return LayerRenderer;
		}(maptalks.renderer.CanvasRenderer);

		Layer$4.registerRenderer('canvas', LayerRenderer);
	}

	var Layer$5 = Layer$4;

	/**
	 * MapV for AMap
	 * @author sakitam-fdd - https://github.com/sakitam-fdd
	 */

	/**
	 * create canvas
	 * @param width
	 * @param height
	 * @param Canvas
	 * @returns {HTMLCanvasElement}
	 */
	var createCanvas = function createCanvas(width, height, Canvas) {
		if (typeof document !== 'undefined') {
			var canvas = document.createElement('canvas');
			canvas.width = width;
			canvas.height = height;
			return canvas;
		} else {
			// create a new canvas instance in node.js
			// the canvas class needs to have a default constructor without any parameter
			return new Canvas(width, height);
		}
	};

	var Layer$6 = function(_BaseLayer) {
		inherits(Layer, _BaseLayer);

		function Layer() {
			var map = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
			var dataSet = arguments[1];
			var options = arguments[2];
			classCallCheck(this, Layer);

			var _this = possibleConstructorReturn(this, (Layer.__proto__ || Object.getPrototypeOf(Layer)).call(this, map,
				dataSet, options));

			_this.options = options;

			/**
			 * internal
			 * @type {{canvas: null, devicePixelRatio: number}}
			 */
			_this.canvasLayer = {
				canvas: null,
				devicePixelRatio: window.devicePixelRatio
			};

			/**
			 * canvas layer
			 * @type {null}
			 * @private
			 */
			_this.layer_ = null;

			_this.initDataRange(options);
			_this.initAnimator();
			_this.onEvents();
			map.on('complete', function() {
				this.init(map, options);
				this.argCheck(options);
			}, _this);
			return _this;
		}

		/**
		 * init mapv layer
		 * @param map
		 * @param options
		 */


		createClass(Layer, [{
			key: "init",
			value: function init(map, options) {
				if (map) {
					this.map = map;
					this.context = this.options.context || '2d';
					this.getCanvasLayer();
				} else {
					throw new Error('not map object');
				}
			}

			/**
			 * update layer
			 * @param time
			 * @private
			 */

		}, {
			key: "_canvasUpdate",
			value: function _canvasUpdate(time) {
				this.render(this.canvasLayer.canvas, time);
			}

			/**
			 * render layer
			 * @param canvas
			 * @param time
			 * @returns {Layer}
			 */

		}, {
			key: "render",
			value: function render(canvas, time) {
				if (!canvas) return;
				var map = this.map;
				var context = canvas.getContext(this.context);
				var animationOptions = this.options.animation;
				if (this.isEnabledTime()) {
					if (time === undefined) {
						clear(context);
						return this;
					}
					if (this.context === '2d') {
						context.save();
						context.globalCompositeOperation = 'destination-out';
						context.fillStyle = 'rgba(0, 0, 0, .1)';
						context.fillRect(0, 0, context.canvas.width, context.canvas.height);
						context.restore();
					}
				} else {
					clear(context);
				}

				if (this.context === '2d') {
					for (var key in this.options) {
						context[key] = this.options[key];
					}
				} else {
					context.clear(context.COLOR_BUFFER_BIT);
				}
				var dataGetOptions = {
					transferCoordinate: function transferCoordinate(coordinate) {
						var _pixel = map.lngLatToContainer(new AMap.LngLat(coordinate[0], coordinate[1]));
						return [_pixel['x'], _pixel['y']];
					}
				};

				if (time !== undefined) {
					dataGetOptions.filter = function(item) {
						var trails = animationOptions.trails || 10;
						if (time && item.time > time - trails && item.time < time) {
							return true;
						} else {
							return false;
						}
					};
				}

				var data = this.dataSet.get(dataGetOptions);
				this.processData(data);

				if (this.options.unit === 'm') {
					if (this.options.size) {
						this.options._size = this.options.size / zoomUnit;
					}
					if (this.options.width) {
						this.options._width = this.options.width / zoomUnit;
					}
					if (this.options.height) {
						this.options._height = this.options.height / zoomUnit;
					}
				} else {
					this.options._size = this.options.size;
					this.options._height = this.options.height;
					this.options._width = this.options.width;
				}

				this.drawContext(context, new DataSet(data), this.options, {
					x: 0,
					y: 0
				});
				this.options.updateCallback && this.options.updateCallback(time);
				return this;
			}

			/**
			 * get canvas layer
			 */

		}, {
			key: "getCanvasLayer",
			value: function getCanvasLayer() {
				if (!this.canvasLayer.canvas && !this.layer_) {
					var canvas = this.canvasFunction();
					var bounds = this.map.getBounds();
					this.layer_ = new AMap.CanvasLayer({
						canvas: canvas,
						bounds: this.options.bounds || bounds,
						zooms: this.options.zooms || [0, 22]
					});
					this.layer_.setMap(this.map);
					this.map.on('mapmove', this.canvasFunction, this);
					this.map.on('zoomchange', this.canvasFunction, this);
				}
			}

			/**
			 * canvas constructor
			 * @returns {*}
			 */

		}, {
			key: "canvasFunction",
			value: function canvasFunction() {
				var _ref = [this.map.getSize().width, this.map.getSize().height],
					width = _ref[0],
					height = _ref[1];

				if (!this.canvasLayer.canvas) {
					this.canvasLayer.canvas = createCanvas(width, height);
				} else {
					this.canvasLayer.canvas.width = width;
					this.canvasLayer.canvas.height = height;
					var bounds = this.map.getBounds();
					if (this.layer_) {
						this.layer_.setBounds(this.options.bounds || bounds);
					}
				}
				this.render(this.canvasLayer.canvas);
				return this.canvasLayer.canvas;
			}

			/**
			 * remove layer
			 */

		}, {
			key: "removeLayer",
			value: function removeLayer() {
				if (!this.map) return;
				this.unEvents();
				this.map.removeLayer(this.layer_);
				delete this.map;
				delete this.layer_;
				delete this.canvasLayer.canvas;
			}
		}, {
			key: "getContext",
			value: function getContext() {
				return this.canvasLayer.canvas.getContext(this.context);
			}

			/**
			 * handle click event
			 * @param event
			 */

		}, {
			key: "clickEvent",
			value: function clickEvent(event) {
				var pixel = event.pixel;
				get(Layer.prototype.__proto__ || Object.getPrototypeOf(Layer.prototype), "clickEvent", this).call(this,
					pixel, event);
			}

			/**
			 * handle mousemove/pointermove event
			 * @param event
			 */

		}, {
			key: "mousemoveEvent",
			value: function mousemoveEvent(event) {
				var pixel = event.pixel;
				get(Layer.prototype.__proto__ || Object.getPrototypeOf(Layer.prototype), "mousemoveEvent", this).call(this,
					pixel, event);
			}

			/**
			 * add animator event
			 */

		}, {
			key: "addAnimatorEvent",
			value: function addAnimatorEvent() {
				this.map.on('movestart', this.animatorMovestartEvent, this);
				this.map.on('moveend', this.animatorMoveendEvent, this);
			}

			/**
			 * bind event
			 */

		}, {
			key: "onEvents",
			value: function onEvents() {
				var map = this.map;
				this.unEvents();
				if (this.options.methods) {
					if (this.options.methods.click) {
						map.on('click', this.clickEvent, this);
					}
					if (this.options.methods.mousemove) {
						map.on('mousemove', this.mousemoveEvent, this);
					}
				}
			}

			/**
			 * unbind events
			 */

		}, {
			key: "unEvents",
			value: function unEvents() {
				var map = this.map;
				if (this.options.methods) {
					if (this.options.methods.click) {
						map.off('click', this.clickEvent, this);
					}
					if (this.options.methods.mousemove) {
						map.off('mousemove', this.mousemoveEvent, this);
					}
				}
			}
		}]);
		return Layer;
	}(BaseLayer);

	/**
	 * MapV for openlayers (https://openlayers.org)
	 * @author sakitam-fdd - https://github.com/sakitam-fdd
	 */

	/**
	 * create canvas
	 * @param width
	 * @param height
	 * @returns {HTMLCanvasElement}
	 */
	var createCanvas$1 = function createCanvas(width, height) {
		if (typeof document !== 'undefined') {
			var canvas = document.createElement('canvas');
			canvas.width = width;
			canvas.height = height;
			return canvas;
		} else {
			// create a new canvas instance in node.js
			// the canvas class needs to have a default constructor without any parameter
		}
	};

	var Layer$8 = function(_BaseLayer) {
		inherits(Layer, _BaseLayer);

		function Layer() {
			var map = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
			var dataSet = arguments[1];
			var options = arguments[2];
			classCallCheck(this, Layer);

			var _this = possibleConstructorReturn(this, (Layer.__proto__ || Object.getPrototypeOf(Layer)).call(this, map,
				dataSet, options));

			_this.options = options;

			/**
			 * internal
			 * @type {{canvas: null, devicePixelRatio: number}}
			 */
			_this.canvasLayer = {
				canvas: null,
				devicePixelRatio: window.devicePixelRatio

				/**
				 * cavnas layer
				 * @type {null}
				 * @private
				 */
			};
			_this.layer_ = null;

			/**
			 * previous cursor
			 * @type {undefined}
			 * @private
			 */
			_this.previousCursor_ = undefined;

			_this.init(map, options);
			_this.argCheck(options);
			return _this;
		}

		/**
		 * init mapv layer
		 * @param map
		 * @param options
		 */


		createClass(Layer, [{
			key: "init",
			value: function init(map, options) {
				if (map && map instanceof ol.Map) {
					this.$Map = map;
					this.context = this.options.context || '2d';
					this.getCanvasLayer();
					this.initDataRange(options);
					this.initAnimator();
					this.onEvents();
				} else {
					throw new Error('not map object');
				}
			}

			/**
			 * update layer
			 * @param time
			 * @private
			 */

		}, {
			key: "_canvasUpdate",
			value: function _canvasUpdate(time) {
				this.render(this.canvasLayer.canvas, time);
			}

			/**
			 * render layer
			 * @param canvas
			 * @param time
			 * @returns {Layer}
			 */

		}, {
			key: "render",
			value: function render(canvas, time) {
				var map = this.$Map;
				var context = canvas.getContext(this.context);
				var animationOptions = this.options.animation;
				var _projection = this.options.hasOwnProperty('projection') ? this.options.projection : 'EPSG:4326';
				if (this.isEnabledTime()) {
					if (time === undefined) {
						clear(context);
						return this;
					}
					if (this.context === '2d') {
						context.save();
						context.globalCompositeOperation = 'destination-out';
						context.fillStyle = 'rgba(0, 0, 0, .1)';
						context.fillRect(0, 0, context.canvas.width, context.canvas.height);
						context.restore();
					}
				} else {
					clear(context);
				}

				if (this.context === '2d') {
					for (var key in this.options) {
						context[key] = this.options[key];
					}
				} else {
					context.clear(context.COLOR_BUFFER_BIT);
				}
				var dataGetOptions = {
					transferCoordinate: function transferCoordinate(coordinate) {
						return map.getPixelFromCoordinate(ol.proj.transform(coordinate, _projection, 'EPSG:4326'));
					}
				};

				if (time !== undefined) {
					dataGetOptions.filter = function(item) {
						var trails = animationOptions.trails || 10;
						if (time && item.time > time - trails && item.time < time) {
							return true;
						} else {
							return false;
						}
					};
				}

				var data = this.dataSet.get(dataGetOptions);
				this.processData(data);

				if (this.options.unit === 'm') {
					if (this.options.size) {
						this.options._size = this.options.size / zoomUnit;
					}
					if (this.options.width) {
						this.options._width = this.options.width / zoomUnit;
					}
					if (this.options.height) {
						this.options._height = this.options.height / zoomUnit;
					}
				} else {
					this.options._size = this.options.size;
					this.options._height = this.options.height;
					this.options._width = this.options.width;
				}

				this.drawContext(context, new DataSet(data), this.options, {
					x: 0,
					y: 0
				});
				this.options.updateCallback && this.options.updateCallback(time);
				return this;
			}

			/**
			 * get canvas layer
			 */

		}, {
			key: "getCanvasLayer",
			value: function getCanvasLayer() {
				if (!this.canvasLayer.canvas && !this.layer_) {
					var extent = this.getMapExtent();
					this.layer_ = new ol.layer.Image({
						layerName: this.options.layerName,
						minResolution: this.options.minResolution,
						maxResolution: this.options.maxResolution,
						zIndex: this.options.zIndex,
						extent: extent,
						source: new ol.source.ImageCanvas({
							canvasFunction: this.canvasFunction.bind(this),
							projection: this.options.hasOwnProperty('projection') ? this.options.projection : 'EPSG:4326',
							ratio: this.options.hasOwnProperty('ratio') ? this.options.ratio : 1
						})
					});
					this.$Map.addLayer(this.layer_);
					this.$Map.un('precompose', this.reRender, this);
					this.$Map.on('precompose', this.reRender, this);
				}
			}

			/**
			 * re render
			 */

		}, {
			key: "reRender",
			value: function reRender() {
				if (!this.layer_) return;
				var extent = this.getMapExtent();
				this.layer_.setExtent(extent);
			}

			/**
			 * canvas constructor
			 * @param extent
			 * @param resolution
			 * @param pixelRatio
			 * @param size
			 * @param projection
			 * @returns {*}
			 */

		}, {
			key: "canvasFunction",
			value: function canvasFunction(extent, resolution, pixelRatio, size, projection) {
				if (!this.canvasLayer.canvas) {
					this.canvasLayer.canvas = createCanvas$1(size[0], size[1]);
				} else {
					this.canvasLayer.canvas.width = size[0];
					this.canvasLayer.canvas.height = size[1];
				}
				this.render(this.canvasLayer.canvas);
				return this.canvasLayer.canvas;
			}

			/**
			 * get map current extent
			 * @returns {Array}
			 */

		}, {
			key: "getMapExtent",
			value: function getMapExtent() {
				var size = this.$Map.getSize();
				return this.$Map.getView().calculateExtent(size);
			}

			/**
			 * add layer to map
			 * @param map
			 */

		}, {
			key: "addTo",
			value: function addTo(map) {
				this.init(map, this.options);
			}

			/**
			 * remove layer
			 */

		}, {
			key: "removeLayer",
			value: function removeLayer() {
				if (!this.$Map) return;
				this.unEvents();
				this.$Map.un('precompose', this.reRender, this);
				this.$Map.removeLayer(this.layer_);
				delete this.$Map;
				delete this.layer_;
				delete this.canvasLayer.canvas;
			}
		}, {
			key: "getContext",
			value: function getContext() {
				return this.canvasLayer.canvas.getContext(this.context);
			}

			/**
			 * handle click event
			 * @param event
			 */

		}, {
			key: "clickEvent",
			value: function clickEvent(event) {
				var pixel = event.pixel;
				get(Layer.prototype.__proto__ || Object.getPrototypeOf(Layer.prototype), "clickEvent", this).call(this, {
					x: pixel[0],
					y: pixel[1]
				}, event);
			}

			/**
			 * handle mousemove/pointermove event
			 * @param event
			 */

		}, {
			key: "mousemoveEvent",
			value: function mousemoveEvent(event) {
				var pixel = event.pixel;
				get(Layer.prototype.__proto__ || Object.getPrototypeOf(Layer.prototype), "mousemoveEvent", this).call(this, {
					x: pixel[0],
					y: pixel[1]
				}, event);
			}

			/**
			 * add animator event
			 */

		}, {
			key: "addAnimatorEvent",
			value: function addAnimatorEvent() {
				this.$Map.on('movestart', this.animatorMovestartEvent, this);
				this.$Map.on('moveend', this.animatorMoveendEvent, this);
			}

			/**
			 * bind event
			 */

		}, {
			key: "onEvents",
			value: function onEvents() {
				var map = this.$Map;
				this.unEvents();
				if (this.options.methods) {
					if (this.options.methods.click) {
						map.on('click', this.clickEvent, this);
					}
					if (this.options.methods.mousemove) {
						map.on('pointermove', this.mousemoveEvent, this);
					}
				}
			}

			/**
			 * unbind events
			 */

		}, {
			key: "unEvents",
			value: function unEvents() {
				var map = this.$Map;
				if (this.options.methods) {
					if (this.options.methods.click) {
						map.un('click', this.clickEvent, this);
					}
					if (this.options.methods.pointermove) {
						map.un('pointermove', this.mousemoveEvent, this);
					}
				}
			}

			/**
			 * set map cursor
			 * @param cursor
			 * @param feature
			 */

		}, {
			key: "setDefaultCursor",
			value: function setDefaultCursor(cursor, feature) {
				if (!this.$Map) return;
				var element = this.$Map.getTargetElement();
				if (feature) {
					if (element.style.cursor !== cursor) {
						this.previousCursor_ = element.style.cursor;
						element.style.cursor = cursor;
					}
				} else if (this.previousCursor_ !== undefined) {
					element.style.cursor = this.previousCursor_;
					this.previousCursor_ = undefined;
				}
			}
		}]);
		return Layer;
	}(BaseLayer);

	// https://github.com/SuperMap/iClient-JavaScript
	/**
	 * @class MapVRenderer
	 * @classdesc 地图渲染类。
	 * @category Visualization MapV
	 * @private
	 * @extends mapv.BaseLayer
	 * @param {L.Map} map - 待渲染的地图。
	 * @param {L.Layer} layer - 待渲染的图层。
	 * @param {DataSet} dataSet - 待渲染的数据集。
	 * @param {Object} options - 渲染的参数。
	 */
	var MapVRenderer = function(_BaseLayer) {
		inherits(MapVRenderer, _BaseLayer);

		function MapVRenderer(map, layer, dataSet, options) {
			classCallCheck(this, MapVRenderer);

			var _this = possibleConstructorReturn(this, (MapVRenderer.__proto__ || Object.getPrototypeOf(MapVRenderer)).call(
				this, map, dataSet, options));

			if (!BaseLayer) {
				return possibleConstructorReturn(_this);
			}

			var self = _this;
			options = options || {};

			self.init(options);
			self.argCheck(options);
			_this.canvasLayer = layer;
			_this.clickEvent = _this.clickEvent.bind(_this);
			_this.mousemoveEvent = _this.mousemoveEvent.bind(_this);
			_this._moveStartEvent = _this.moveStartEvent.bind(_this);
			_this._moveEndEvent = _this.moveEndEvent.bind(_this);
			_this._zoomStartEvent = _this.zoomStartEvent.bind(_this);
			_this.bindEvent();
			return _this;
		}

		/**
		 * @function MapVRenderer.prototype.clickEvent
		 * @description 点击事件。
		 * @param {Object} e - 触发对象。
		 */


		createClass(MapVRenderer, [{
			key: 'clickEvent',
			value: function clickEvent(e) {
				var offset = this.map.containerPointToLayerPoint([0, 0]);
				var devicePixelRatio = this.devicePixelRatio = this.canvasLayer.devicePixelRatio = window.devicePixelRatio;
				var pixel = e.layerPoint;
				get(MapVRenderer.prototype.__proto__ || Object.getPrototypeOf(MapVRenderer.prototype), 'clickEvent', this).call(
					this, L.point((pixel.x - offset.x) / devicePixelRatio, (pixel.y - offset.y) / devicePixelRatio), e);
			}

			/**
			 * @function MapVRenderer.prototype.mousemoveEvent
			 * @description 鼠标移动事件。
			 * @param {Object} e - 触发对象。
			 */

		}, {
			key: 'mousemoveEvent',
			value: function mousemoveEvent(e) {
				var pixel = e.layerPoint;
				get(MapVRenderer.prototype.__proto__ || Object.getPrototypeOf(MapVRenderer.prototype), 'mousemoveEvent',
					this).call(this, pixel, e);
			}

			/**
			 * @function MapVRenderer.prototype.bindEvent
			 * @description 绑定鼠标移动和鼠标点击事件。
			 * @param {Object} e - 触发对象。
			 */

		}, {
			key: 'bindEvent',
			value: function bindEvent() {
				var map = this.map;

				if (this.options.methods) {
					if (this.options.methods.click) {
						map.on('click', this.clickEvent);
					}
					if (this.options.methods.mousemove) {
						map.on('mousemove', this.mousemoveEvent);
					}
				}
				this.map.on('movestart', this._moveStartEvent);
				this.map.on('moveend', this._moveEndEvent);
				this.map.on('zoomstart', this._zoomStartEvent);
			}
			/**
			 * @function MapVRenderer.prototype.destroy
			 * @description 释放资源。
			 */

		}, {
			key: 'destroy',
			value: function destroy() {
				this.unbindEvent();
				this.clearData();
				this.animator && this.animator.stop();
				this.animator = null;
				this.canvasLayer = null;
			}
			/**
			 * @function MapVRenderer.prototype.unbindEvent
			 * @description 解绑鼠标移动和鼠标滑动触发的事件。
			 * @param {Object} e - 触发对象。
			 */

		}, {
			key: 'unbindEvent',
			value: function unbindEvent() {
				var map = this.map;

				if (this.options.methods) {
					if (this.options.methods.click) {
						map.off('click', this.clickEvent);
					}
					if (this.options.methods.mousemove) {
						map.off('mousemove', this.mousemoveEvent);
					}
				}
				this.map.off('movestart', this._moveStartEvent);
				this.map.off('moveend', this._moveEndEvent);
				this.map.off('zoomstart', this._zoomStartEvent);
			}

			/**
			 * @function MapVRenderer.prototype.getContext
			 * @description 获取信息。
			 */

		}, {
			key: 'getContext',
			value: function getContext() {
				return this.canvasLayer.getCanvas().getContext(this.context);
			}

			/**
			 * @function MapVRenderer.prototype.addData
			 * @description 添加数据。
			 * @param {Object} data - 待添加的数据。
			 * @param  {Object} options - 待添加的数据信息。
			 */

		}, {
			key: 'addData',
			value: function addData(data, options) {
				var _data = data;
				if (data && data.get) {
					_data = data.get();
				}
				this.dataSet.add(_data);
				this.update({
					options: options
				});
			}

			/**
			 * @function MapVRenderer.prototype.update
			 * @description 更新图层。
			 * @param {Object} opt - 待更新的数据。
			 * @param {Object} opt.data - mapv数据集。
			 * @param {Object} opt.options - mapv绘制参数。
			 */

		}, {
			key: 'update',
			value: function update(opt) {
				var update = opt || {};
				var _data = update.data;
				if (_data && _data.get) {
					_data = _data.get();
				}
				if (_data != undefined) {
					this.dataSet.set(_data);
				}
				get(MapVRenderer.prototype.__proto__ || Object.getPrototypeOf(MapVRenderer.prototype), 'update', this).call(
					this, {
						options: update.options
					});
			}

			/**
			 * @function MapVRenderer.prototype.getData
			 * @description 获取数据
			 */

		}, {
			key: 'getData',
			value: function getData() {
				return this.dataSet;
			}

			/**
			 * @function MapVRenderer.prototype.removeData
			 * @description 删除符合过滤条件的数据。
			 * @param {Function} filter - 过滤条件。条件参数为数据项，返回值为 true，表示删除该元素；否则表示不删除。
			 */

		}, {
			key: 'removeData',
			value: function removeData(_filter) {
				if (!this.dataSet) {
					return;
				}
				var newData = this.dataSet.get({
					filter: function filter(data) {
						return _filter != null && typeof _filter === "function" ? !_filter(data) : true;
					}
				});
				this.dataSet.set(newData);
				this.update({
					options: null
				});
			}

			/**
			 * @function MapVRenderer.prototype.clearData
			 * @description 清除数据
			 */

		}, {
			key: 'clearData',
			value: function clearData() {
				this.dataSet && this.dataSet.clear();
				this.update({
					options: null
				});
			}
		}, {
			key: '_canvasUpdate',
			value: function _canvasUpdate(time) {
				if (!this.canvasLayer) {
					return;
				}

				var self = this;

				var animationOptions = self.options.animation;

				var context = this.getContext();
				var map = this.map;
				if (self.isEnabledTime()) {
					if (time === undefined) {
						this.clear(context);
						return;
					}
					if (this.context === '2d') {
						context.save();
						context.globalCompositeOperation = 'destination-out';
						context.fillStyle = 'rgba(0, 0, 0, .1)';
						context.fillRect(0, 0, context.canvas.width, context.canvas.height);
						context.restore();
					}
				} else {
					this.clear(context);
				}

				if (this.context === '2d') {
					for (var key in self.options) {
						context[key] = self.options[key];
					}
				} else {
					context.clear(context.COLOR_BUFFER_BIT);
				}

				if (self.options.minZoom && map.getZoom() < self.options.minZoom || self.options.maxZoom && map.getZoom() >
					self.options.maxZoom) {
					return;
				}

				var bounds = map.getBounds();
				//获取当前像素下的地理范围
				var dw = bounds.getEast() - bounds.getWest();
				var dh = bounds.getNorth() - bounds.getSouth();
				var mapCanvas = map.getSize();

				var resolutionX = dw / mapCanvas.x,
					resolutionY = dh / mapCanvas.y;
				//var centerPx = map.latLngToLayerPoint(map.getCenter());

				//获取屏幕左上角的地理坐标坐标
				//左上角屏幕坐标为0,0
				var topLeft = this.canvasLayer.getTopLeft();

				var topLeftPX = map.latLngToContainerPoint(topLeft);
				// 获取精确的像素坐标. https://github.com/SuperMap/iClient-JavaScript/blob/eacc26952b8915bba0122db751d766056c5fb24d/src/leaflet/core/Base.js
				// var topLeftPX = map.latLngToAccurateContainerPoint(topLeft);
				// var lopLeft = map.containerPointToLatLng([0, 0]);
				var dataGetOptions = {
					transferCoordinate: function transferCoordinate(coordinate) {
						var offset;
						if (self.context === '2d') {
							offset = map.latLngToContainerPoint(L.latLng(coordinate[1], coordinate[0]));
							// offset = map.latLngToAccurateContainerPoint(L.latLng(coordinate[1], coordinate[0]));
						} else {
							offset = {
								'x': (coordinate[0] - topLeft.lng) / resolutionX,
								'y': (topLeft.lat - coordinate[1]) / resolutionY
							};
						}
						var pixel = {
							x: offset.x - topLeftPX.x,
							y: offset.y - topLeftPX.y
						};
						return [pixel.x, pixel.y];
					}
				};

				if (time !== undefined) {
					dataGetOptions.filter = function(item) {
						var trails = animationOptions.trails || 10;
						return time && item.time > time - trails && item.time < time;
					};
				}

				var data = self.dataSet.get(dataGetOptions);

				this.processData(data);

				self.options._size = self.options.size;

				var worldPoint = map.latLngToContainerPoint(L.latLng(0, 0));
				var pixel = {
					x: worldPoint.x - topLeftPX.x,
					y: worldPoint.y - topLeftPX.y
				};
				this.drawContext(context, data, self.options, pixel);

				self.options.updateCallback && self.options.updateCallback(time);
			}
		}, {
			key: 'init',
			value: function init(options) {

				var self = this;

				self.options = options;

				this.initDataRange(options);

				this.context = self.options.context || '2d';

				if (self.options.zIndex) {
					this.canvasLayer && this.canvasLayer.setZIndex(self.options.zIndex);
				}

				this.initAnimator();
			}
		}, {
			key: 'addAnimatorEvent',
			value: function addAnimatorEvent() {}

			/**
			 * @function MapVRenderer.prototype.moveStartEvent
			 * @description 开始移动事件。
			 */

		}, {
			key: 'moveStartEvent',
			value: function moveStartEvent() {
				var animationOptions = this.options.animation;
				if (this.isEnabledTime() && this.animator) {
					this.steps.step = animationOptions.stepsRange.start;
					this._hide();
				}
			}

			/**
			 * @function MapVRenderer.prototype.moveEndEvent
			 * @description 结束移动事件。
			 */

		}, {
			key: 'moveEndEvent',
			value: function moveEndEvent() {
				this.canvasLayer.draw();
				this._show();
			}

			/**
			 * @function MapVRenderer.prototype.zoomStartEvent
			 * @description 隐藏渲染样式。
			 */

		}, {
			key: 'zoomStartEvent',
			value: function zoomStartEvent() {
				this._hide();
			}

			/**
			 * @function MapVRenderer.prototype.clear
			 * @description 清除信息。
			 * @param {string} context - 指定要清除的信息。
			 */

		}, {
			key: 'clear',
			value: function clear(context) {
				context && context.clearRect && context.clearRect(0, 0, context.canvas.width, context.canvas.height);
			}
		}, {
			key: '_hide',
			value: function _hide() {
				this.canvasLayer.canvas.style.display = 'none';
			}
		}, {
			key: '_show',
			value: function _show() {
				this.canvasLayer.canvas.style.display = 'block';
			}

			/**
			 * @function MapVRenderer.prototype.draw
			 * @description 绘制渲染
			 */

		}, {
			key: 'draw',
			value: function draw() {
				this.canvasLayer.draw();
			}
		}]);
		return MapVRenderer;
	}(BaseLayer);

	var mapVLayer;
	if (typeof L !== 'undefined') {
		/**
		 * @class mapVLayer
		 * @classdesc MapV 图层。
		 * @category Visualization MapV
		 * @extends {L.Layer}
		 * @param {mapv.DataSet} dataSet - MapV 图层数据集。
		 * @param {Object} mapVOptions - MapV 图层参数。
		 * @param {Object} options - 参数。
		 * @param {string} [options.attributionPrefix] - 版权信息前缀。
		 * @param {string} [options.attribution='© 2018 百度 MapV'] - 版权信息。
		 * @fires mapVLayer#loaded
		 */
		var MapVLayer = L.Layer.extend({

			options: {
				attributionPrefix: null,
				attribution: ''
			},

			initialize: function initialize(dataSet, mapVOptions, options) {
				options = options || {};
				this.dataSet = dataSet || {};
				this.mapVOptions = mapVOptions || {};
				this.render = this.render.bind(this);
				L.Util.setOptions(this, options);
				if (this.options.attributionPrefix) {
					this.options.attribution = this.options.attributionPrefix + this.options.attribution;
				}

				this.canvas = this._createCanvas();
				L.stamp(this);
			},

			/**
			 * @private
			 * @function mapVLayer.prototype.onAdd
			 * @description 添加地图图层。
			 * @param {L.Map} map - 要添加的地图。
			 */
			onAdd: function onAdd(map) {
				this._map = map;
				var overlayPane = this.getPane();
				var container = this.container = L.DomUtil.create("div", "leaflet-layer leaflet-zoom-animated", overlayPane);
				container.appendChild(this.canvas);
				var size = map.getSize();
				container.style.width = size.x + "px";
				container.style.height = size.y + "px";
				this.renderer = new MapVRenderer(map, this, this.dataSet, this.mapVOptions);
				this.draw();
				/**
				 * @event mapVLayer#loaded
				 * @description 图层添加完成之后触发。
				 */
				this.fire("loaded");
			},

			// _hide: function () {
			//     this.canvas.style.display = 'none';
			// },

			// _show: function () {
			//     this.canvas.style.display = 'block';
			// },

			/**
			 * @private
			 * @function mapVLayer.prototype.onRemove
			 * @description 删除地图图层。
			 */
			onRemove: function onRemove() {
				L.DomUtil.remove(this.container);
				this.renderer.destroy();
			},

			/**
			 * @function mapVLayer.prototype.addData
			 * @description 追加数据。
			 * @param {Object} data - 要追加的数据。
			 * @param {Object} options - 要追加的值。
			 */
			addData: function addData(data, options) {
				this.renderer.addData(data, options);
			},

			/**
			 * @function mapVLayer.prototype.update
			 * @description 更新图层。
			 * @param {Object} opt - 待更新的数据。
			 * @param {Object} data - mapv 数据集。
			 * @param {Object} options - mapv 绘制参数。
			 */
			update: function update(opt) {
				this.renderer.update(opt);
			},

			/**
			 * @function mapVLayer.prototype.getData
			 * @description 获取数据。
			 * @returns {mapv.DataSet} mapv 数据集。
			 */
			getData: function getData() {
				if (this.renderer) {
					this.dataSet = this.renderer.getData();
				}
				return this.dataSet;
			},

			/**
			 * @function mapVLayer.prototype.removeData
			 * @description 删除符合过滤条件的数据。
			 * @param {Function} filter - 过滤条件。条件参数为数据项，返回值为 true，表示删除该元素；否则表示不删除。
			 * @example
			 *  filter=function(data){
			 *    if(data.id=="1"){
			 *      return true
			 *    }
			 *    return false;
			 *  }
			 */
			removeData: function removeData(filter) {
				this.renderer && this.renderer.removeData(filter);
			},

			/**
			 * @function mapVLayer.prototype.clearData
			 * @description 清除数据。
			 */
			clearData: function clearData() {
				this.renderer.clearData();
			},

			/**
			 * @function mapVLayer.prototype.draw
			 * @description 绘制图层。
			 */
			draw: function draw() {
				return this._reset();
			},

			/**
			 * @function mapVLayer.prototype.setZIndex
			 * @description 设置 canvas 层级。
			 * @param {number} zIndex - canvas 层级。
			 */
			setZIndex: function setZIndex(zIndex) {
				this.canvas.style.zIndex = zIndex;
			},

			/**
			 * @function mapVLayer.prototype.render
			 * @description 渲染。
			 */
			render: function render() {
				this.renderer._canvasUpdate();
			},

			/**
			 * @function mapVLayer.prototype.getCanvas
			 * @description 获取 canvas。
			 * @returns {HTMLElement} 返回 mapV 图层包含的 canvas 对象。
			 */
			getCanvas: function getCanvas() {
				return this.canvas;
			},

			/**
			 * @function mapVLayer.prototype.getContainer
			 * @description 获取容器。
			 * @returns {HTMLElement} 返回包含 mapV 图层的 dom 对象。
			 */
			getContainer: function getContainer() {
				return this.container;
			},

			/**
			 * @function mapVLayer.prototype.getTopLeft
			 * @description 获取左上角坐标。
			 * @returns {L.Bounds} 返回左上角坐标。
			 */
			getTopLeft: function getTopLeft() {
				var map = this._map;
				var topLeft;
				if (map) {
					var bounds = map.getBounds();
					topLeft = bounds.getNorthWest();
				}
				return topLeft;
			},

			_createCanvas: function _createCanvas() {
				var canvas = document.createElement('canvas');
				canvas.style.position = 'absolute';
				canvas.style.top = 0 + "px";
				canvas.style.left = 0 + "px";
				canvas.style.pointerEvents = "none";
				canvas.style.zIndex = this.options.zIndex || 600;
				var global$2 = typeof window === 'undefined' ? {} : window;
				var devicePixelRatio = this.devicePixelRatio = global$2.devicePixelRatio;
				if (!this.mapVOptions.context || this.mapVOptions.context === '2d') {
					canvas.getContext('2d').scale(devicePixelRatio, devicePixelRatio);
				}
				return canvas;
			},

			_resize: function _resize() {
				var canvas = this.canvas;
				if (!canvas) {
					return;
				}

				var map = this._map;
				var size = map.getSize();
				canvas.width = size.x;
				canvas.height = size.y;
				canvas.style.width = size.x + 'px';
				canvas.style.height = size.y + 'px';
				var bounds = map.getBounds();
				var topLeft = map.latLngToLayerPoint(bounds.getNorthWest());
				L.DomUtil.setPosition(canvas, topLeft);
			},

			_reset: function _reset() {
				this._resize();
				this._render();
			},
			redraw: function redraw() {
				this._resize();
				this._render();
			},
			_render: function _render() {
				this.render();
			}

		});

		mapVLayer = function mapVLayer(dataSet, mapVOptions, options) {
			return new MapVLayer(dataSet, mapVOptions, options);
		};
	}
	var mapVLayer$1 = mapVLayer;

	var MapVRenderer$1 = function(_BaseLayer) {
		inherits(MapVRenderer, _BaseLayer);

		/**
		 * Creates an instance of MapVRenderer.
		 * @param {*} viewer cesium viewer
		 * @param {*} dataset mapv dataset
		 * @param {*} option mapvOptions
		 * @param {*} mapVLayer
		 * @memberof MapVRenderer
		 */
		function MapVRenderer(viewer, dataset, option, mapVLayer) {
			classCallCheck(this, MapVRenderer);

			var _this = possibleConstructorReturn(this, (MapVRenderer.__proto__ || Object.getPrototypeOf(MapVRenderer)).call(
				this, viewer, dataset, option));

			if (!BaseLayer) {
				return possibleConstructorReturn(_this);
			}
			_this.map = viewer, _this.scene = viewer.scene, _this.dataSet = dataset;
			option = option || {}, _this.init(option), _this.argCheck(option), _this.initDevicePixelRatio(), _this.canvasLayer =
				mapVLayer, _this.stopAniamation = !1, _this.animation = option.animation, _this.clickEvent = _this.clickEvent.bind(
					_this), _this.mousemoveEvent = _this.mousemoveEvent.bind(_this), _this.bindEvent();
			return _this;
		}

		createClass(MapVRenderer, [{
			key: "initDevicePixelRatio",
			value: function initDevicePixelRatio() {
				this.devicePixelRatio = window.devicePixelRatio || 1;
			}
		}, {
			key: "clickEvent",
			value: function clickEvent(t) {
				var e = t.point;
				get(MapVRenderer.prototype.__proto__ || Object.getPrototypeOf(MapVRenderer.prototype), "clickEvent", this).call(
					this, e, t);
			}
		}, {
			key: "mousemoveEvent",
			value: function mousemoveEvent(t) {
				var e = t.point;
				get(MapVRenderer.prototype.__proto__ || Object.getPrototypeOf(MapVRenderer.prototype), "mousemoveEvent",
					this).call(this, e, t);
			}
		}, {
			key: "addAnimatorEvent",
			value: function addAnimatorEvent() {}
		}, {
			key: "animatorMovestartEvent",
			value: function animatorMovestartEvent() {
				var t = this.options.animation;
				this.isEnabledTime() && this.animator && (this.steps.step = t.stepsRange.start);
			}
		}, {
			key: "animatorMoveendEvent",
			value: function animatorMoveendEvent() {
				this.isEnabledTime() && this.animator;
			}
		}, {
			key: "bindEvent",
			value: function bindEvent() {
				this.map;
				this.options.methods && (this.options.methods.click, this.options.methods.mousemove);
			}
		}, {
			key: "unbindEvent",
			value: function unbindEvent() {
				var t = this.map;
				this.options.methods && (this.options.methods.click && t.off("click", this.clickEvent), this.options.methods
					.mousemove && t.off("mousemove", this.mousemoveEvent));
			}
		}, {
			key: "getContext",
			value: function getContext() {
				return this.canvasLayer.canvas.getContext(this.context);
			}
		}, {
			key: "init",
			value: function init(t) {
				this.options = t, this.initDataRange(t), this.context = this.options.context || "2d", this.options.zIndex &&
					this.canvasLayer && this.canvasLayer.setZIndex(this.options.zIndex), this.initAnimator();
			}
		}, {
			key: "_canvasUpdate",
			value: function _canvasUpdate(t) {
				this.map;
				var e = this.scene;
				if (this.canvasLayer && !this.stopAniamation) {
					var i = this.options.animation,
						n = this.getContext();
					if (this.isEnabledTime()) {
						if (void 0 === t) return void this.clear(n);
						"2d" === this.context && (n.save(), n.globalCompositeOperation = "destination-out", n.fillStyle =
							"rgba(0, 0, 0, .1)", n.fillRect(0, 0, n.canvas.width, n.canvas.height), n.restore());
					} else this.clear(n);
					if ("2d" === this.context)
						for (var o in this.options) {
							n[o] = this.options[o];
						} else n.clear(n.COLOR_BUFFER_BIT);
					var a = {
						transferCoordinate: function transferCoordinate(t) {
							var i = Cesium.Cartesian3.fromDegrees(t[0], t[1]),
								n = Cesium.SceneTransforms.wgs84ToWindowCoordinates(e, i);
							return void 0 == n ? [-1, -1] : [n.x, n.y];
						}
					};
					void 0 !== t && (a.filter = function(e) {
						var n = i.trails || 10;
						return !!(t && e.time > t - n && e.time < t);
					});
					var c = this.dataSet.get(a);
					this.processData(c), "m" == this.options.unit && this.options.size, this.options._size = this.options.size;
					var h = Cesium.SceneTransforms.wgs84ToWindowCoordinates(e, Cesium.Cartesian3.fromDegrees(0, 0));
					this.drawContext(n, new DataSet(c), this.options, h), this.options.updateCallback && this.options.updateCallback(
						t);
				}
			}
		}, {
			key: "updateData",
			value: function updateData(t, e) {
				var i = t;
				i && i.get && (i = i.get()), void 0 != i && this.dataSet.set(i), get(MapVRenderer.prototype.__proto__ ||
					Object.getPrototypeOf(MapVRenderer.prototype), "update", this).call(this, {
					options: e
				});
			}
		}, {
			key: "addData",
			value: function addData(t, e) {
				var i = t;
				t && t.get && (i = t.get()), this.dataSet.add(i), this.update({
					options: e
				});
			}
		}, {
			key: "getData",
			value: function getData() {
				return this.dataSet;
			}
		}, {
			key: "removeData",
			value: function removeData(t) {
				if (this.dataSet) {
					var e = this.dataSet.get({
						filter: function filter(e) {
							return null == t || "function" != typeof t || !t(e);
						}
					});
					this.dataSet.set(e), this.update({
						options: null
					});
				}
			}
		}, {
			key: "clearData",
			value: function clearData() {
				this.dataSet && this.dataSet.clear(), this.update({
					options: null
				});
			}
		}, {
			key: "draw",
			value: function draw() {
				this.canvasLayer.draw();
			}
		}, {
			key: "clear",
			value: function clear(t) {
				t && t.clearRect && t.clearRect(0, 0, t.canvas.width, t.canvas.height);
			}
		}]);
		return MapVRenderer;
	}(BaseLayer);

	var mapVLayer$2;
	if (typeof Cesium !== 'undefined') {
		var defIndex = 0;
		var r = Cesium;

		var MapVLayer$1 = function() {
			/**
			 *Creates an instance of MapVLayer.
			 * @param {*} viewer
			 * @param {*} dataset
			 * @param {*} options
			 * @param {*} container default viewer.container
			 * @memberof MapVLayer
			 */
			function MapVLayer(viewer, dataset, options, container) {
				classCallCheck(this, MapVLayer);

				this.map = viewer, this.scene = viewer.scene, this.mapvBaseLayer = new MapVRenderer$1(viewer, dataset, options,
						this), this.mapVOptions = options, this.initDevicePixelRatio(), this.canvas = this._createCanvas(), this.render =
					this.render.bind(this);
				if (container) {
					this.container = container;
				} else {
					var inner = viewer.container.querySelector('.cesium-viewer-cesiumWidgetContainer');
					this.container = inner ? inner : viewer.container;
				}
				this.addInnerContainer();

				// void 0 != container ? (this.container = container,
				//     container.appendChild(this.canvas)) : (this.container = viewer.container,
				//         this.addInnerContainer()),
				this.bindEvent();
				this._reset();
			}

			createClass(MapVLayer, [{
				key: 'initDevicePixelRatio',
				value: function initDevicePixelRatio() {
					this.devicePixelRatio = window.devicePixelRatio || 1;
				}
			}, {
				key: 'addInnerContainer',
				value: function addInnerContainer() {
					this.container.appendChild(this.canvas);
				}
			}, {
				key: 'bindEvent',
				value: function bindEvent() {
					var that = this;

					this.innerMoveStart = this.moveStartEvent.bind(this);
					this.innerMoveEnd = this.moveEndEvent.bind(this);
					this.scene.camera.moveStart.addEventListener(this.innerMoveStart, this);
					this.scene.camera.moveEnd.addEventListener(this.innerMoveEnd, this);

					var t = new Cesium.ScreenSpaceEventHandler(this.scene.canvas);

					t.setInputAction(function(t) {
						that.innerMoveEnd();
					}, Cesium.ScreenSpaceEventType.LEFT_UP);
					t.setInputAction(function(t) {
						that.innerMoveEnd();
					}, Cesium.ScreenSpaceEventType.MIDDLE_UP);
					this.handler = t;
				}
			}, {
				key: 'unbindEvent',
				value: function unbindEvent() {
					this.scene.camera.moveStart.removeEventListener(this.innerMoveStart, this);
					this.scene.camera.moveEnd.removeEventListener(this.innerMoveEnd, this);
					this.scene.postRender.removeEventListener(this._reset, this);
					this.handler && (this.handler.destroy(), this.handler = null);
				}
			}, {
				key: 'moveStartEvent',
				value: function moveStartEvent() {
					if (this.mapvBaseLayer) {
						this.mapvBaseLayer.animatorMovestartEvent();
						this.scene.postRender.addEventListener(this._reset, this);
					}
				}
			}, {
				key: 'moveEndEvent',
				value: function moveEndEvent() {
					if (this.mapvBaseLayer) {
						this.scene.postRender.removeEventListener(this._reset, this), this.mapvBaseLayer.animatorMoveendEvent();
						this._reset();
					}
				}
			}, {
				key: 'zoomStartEvent',
				value: function zoomStartEvent() {
					this._unvisiable();
				}
			}, {
				key: 'zoomEndEvent',
				value: function zoomEndEvent() {
					this._unvisiable();
				}
			}, {
				key: 'addData',
				value: function addData(t, e) {
					void 0 != this.mapvBaseLayer && this.mapvBaseLayer.addData(t, e);
				}
			}, {
				key: 'updateData',
				value: function updateData(t, e) {
					void 0 != this.mapvBaseLayer && this.mapvBaseLayer.updateData(t, e);
				}
			}, {
				key: 'getData',
				value: function getData() {
					return this.mapvBaseLayer && (this.dataSet = this.mapvBaseLayer.getData()), this.dataSet;
				}
			}, {
				key: 'removeData',
				value: function removeData(t) {
					void 0 != this.mapvBaseLayer && this.mapvBaseLayer && this.mapvBaseLayer.removeData(t);
				}
			}, {
				key: 'removeAllData',
				value: function removeAllData() {
					void 0 != this.mapvBaseLayer && this.mapvBaseLayer.clearData();
				}
			}, {
				key: '_visiable',
				value: function _visiable() {
					return this.canvas.style.display = "block", this;
				}
			}, {
				key: '_unvisiable',
				value: function _unvisiable() {
					return this.canvas.style.display = "none", this;
				}
			}, {
				key: '_createCanvas',
				value: function _createCanvas() {
					var t = document.createElement("canvas");
					t.id = this.mapVOptions.layerid || "mapv" + defIndex++, t.style.position = "absolute", t.style.top = "0px",
						t.style.left = "0px", t.style.pointerEvents = "none", t.style.zIndex = this.mapVOptions.zIndex || 0, t.width =
						parseInt(this.map.canvas.width), t.height = parseInt(this.map.canvas.height), t.style.width = this.map.canvas
						.style.width, t.style.height = this.map.canvas.style.height;
					var e = this.devicePixelRatio;
					return "2d" == this.mapVOptions.context && t.getContext(this.mapVOptions.context).scale(e, e), t;
				}
			}, {
				key: '_reset',
				value: function _reset() {
					this.resizeCanvas();
					this.fixPosition();
					this.onResize();
					this.render();
				}
			}, {
				key: 'draw',
				value: function draw() {
					this._reset();
				}
			}, {
				key: 'show',
				value: function show() {
					this._visiable();
				}
			}, {
				key: 'hide',
				value: function hide() {
					this._unvisiable();
				}
			}, {
				key: 'destroy',
				value: function destroy() {
					this.remove();
				}
			}, {
				key: 'remove',
				value: function remove() {
					void 0 != this.mapvBaseLayer && (this.removeAllData(), this.mapvBaseLayer.clear(this.mapvBaseLayer.getContext()),
						this.mapvBaseLayer = void 0, this.canvas.parentElement.removeChild(this.canvas));
				}
			}, {
				key: 'update',
				value: function update(t) {
					void 0 != t && this.updateData(t.data, t.options);
				}
			}, {
				key: 'resizeCanvas',
				value: function resizeCanvas() {
					if (void 0 != this.canvas && null != this.canvas) {
						var t = this.canvas;
						t.style.position = "absolute", t.style.top = "0px", t.style.left = "0px", t.width = parseInt(this.map.canvas
								.width), t.height = parseInt(this.map.canvas.height), t.style.width = this.map.canvas.style.width, t.style
							.height = this.map.canvas.style.height;
					}
				}
			}, {
				key: 'fixPosition',
				value: function fixPosition() {}
			}, {
				key: 'onResize',
				value: function onResize() {}
			}, {
				key: 'render',
				value: function render() {
					void 0 != this.mapvBaseLayer && this.mapvBaseLayer._canvasUpdate();
				}
			}]);
			return MapVLayer;
		}();

		mapVLayer$2 = function mapVLayer(viewer, dataSet, mapVOptions, container) {
			return new MapVLayer$1(viewer, dataSet, mapVOptions, container);
		};
	}

	var mapVLayer$3 = mapVLayer$2;

	/**
	 * @author kyle / http://nikai.us/
	 */

	var geojson = {
		getDataSet: function getDataSet(geoJson) {

			var data = [];
			var features = geoJson.features;
			if (features) {
				for (var i = 0; i < features.length; i++) {
					var feature = features[i];
					var geometry = feature.geometry;
					var properties = feature.properties;
					var item = {};
					for (var key in properties) {
						item[key] = properties[key];
					}
					item.geometry = geometry;
					data.push(item);
				}
			}
			return new DataSet(data);
		}
	};

	/**
	 * @author kyle / http://nikai.us/
	 */

	var csv = {
		CSVToArray: function CSVToArray(strData, strDelimiter) {
			// Check to see if the delimiter is defined. If not,
			// then default to comma.
			strDelimiter = strDelimiter || ",";

			// Create a regular expression to parse the CSV values.
			var objPattern = new RegExp(
				// Delimiters.
				"(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +

				// Quoted fields.
				"(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +

				// Standard fields.
				"([^\"\\" + strDelimiter + "\\r\\n]*))", "gi");

			// Create an array to hold our data. Give the array
			// a default empty first row.
			var arrData = [
				[]
			];

			// Create an array to hold our individual pattern
			// matching groups.
			var arrMatches = null;

			// Keep looping over the regular expression matches
			// until we can no longer find a match.
			while (arrMatches = objPattern.exec(strData)) {

				// Get the delimiter that was found.
				var strMatchedDelimiter = arrMatches[1];

				// Check to see if the given delimiter has a length
				// (is not the start of string) and if it matches
				// field delimiter. If id does not, then we know
				// that this delimiter is a row delimiter.
				if (strMatchedDelimiter.length && strMatchedDelimiter !== strDelimiter) {

					// Since we have reached a new row of data,
					// add an empty row to our data array.
					arrData.push([]);
				}

				var strMatchedValue;

				// Now that we have our delimiter out of the way,
				// let's check to see which kind of value we
				// captured (quoted or unquoted).
				if (arrMatches[2]) {

					// We found a quoted value. When we capture
					// this value, unescape any double quotes.
					strMatchedValue = arrMatches[2].replace(new RegExp("\"\"", "g"), "\"");
				} else {

					// We found a non-quoted value.
					strMatchedValue = arrMatches[3];
				}

				// Now that we have our value string, let's add
				// it to the data array.
				arrData[arrData.length - 1].push(strMatchedValue);
			}

			// Return the parsed data.
			return arrData;
		},

		getDataSet: function getDataSet(csvStr, split) {

			var arr = this.CSVToArray(csvStr, split || ',');

			var data = [];

			var header = arr[0];

			for (var i = 1; i < arr.length - 1; i++) {
				var line = arr[i];
				var item = {};
				for (var j = 0; j < line.length; j++) {
					var value = line[j];
					if (header[j] == 'geometry') {
						value = JSON.parse(value);
					}
					item[header[j]] = value;
				}
				data.push(item);
			}

			return new DataSet(data);
		}
	};

	exports.version = version;
	exports.canvasClear = clear;
	exports.canvasResolutionScale = resolutionScale$1;
	exports.canvasDrawSimple = drawSimple;
	exports.canvasDrawHeatmap = drawHeatmap;
	exports.canvasDrawGrid = drawGrid;
	exports.canvasDrawHoneycomb = drawHoneycomb;
	exports.webglDrawSimple = webglDrawSimple;
	exports.webglDrawPoint = point;
	exports.webglDrawLine = line;
	exports.webglDrawPolygon = polygon;
	exports.utilCityCenter = cityCenter;
	exports.utilCurve = curve;
	exports.utilForceEdgeBundling = ForceEdgeBundling;
	exports.utilDataRangeIntensity = Intensity;
	exports.utilDataRangeCategory = Category;
	exports.utilDataRangeChoropleth = Choropleth;
	exports.Map = MapHelper;
	exports.baiduMapCanvasLayer = CanvasLayer;
	exports.baiduMapAnimationLayer = AnimationLayer;
	exports.baiduMapLayer = Layer;
	exports.googleMapCanvasLayer = CanvasLayer$2;
	exports.googleMapLayer = Layer$2;
	exports.MaptalksLayer = Layer$5;
	exports.AMapLayer = Layer$6;
	exports.OpenlayersLayer = Layer$8;
	exports.leafletMapLayer = mapVLayer$1;
	exports.cesiumMapLayer = mapVLayer$3;
	exports.DataSet = DataSet;
	exports.geojson = geojson;
	exports.csv = csv;

	Object.defineProperty(exports, '__esModule', {
		value: true
	});

})));
